<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: salaboy</title>
    <description>The latest articles on DEV Community by salaboy (@salaboy).</description>
    <link>https://dev.to/salaboy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F318655%2Fcde6d81c-0769-4bc2-a916-dfb6a7d61b7e.png</url>
      <title>DEV Community: salaboy</title>
      <link>https://dev.to/salaboy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salaboy"/>
    <language>en</language>
    <item>
      <title>KubeCon &amp; Spring One 2020: From Monoliths to K8s</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Thu, 24 Sep 2020 09:29:09 +0000</pubDate>
      <link>https://dev.to/salaboy/kubecon-spring-one-2020-from-monoliths-to-k8s-2n3k</link>
      <guid>https://dev.to/salaboy/kubecon-spring-one-2020-from-monoliths-to-k8s-2n3k</guid>
      <description>&lt;p&gt;Last month was quite a rollercoaster, I’ve presented at &lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/"&gt;KubeCon EU (Virtual)&lt;/a&gt; and &lt;a href="https://springone.io"&gt;Spring One (Virtual)&lt;/a&gt;. Both conferences were amazing and even that the title of the presentation was different the code examples and material used can be found in the following repository: &lt;a href="https://github.com/salaboy/from-monolith-to-k8s"&gt;https://github.com/salaboy/from-monolith-to-k8s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both conferences were focused on Kubernetes, of course targeting different audiences, which is constant validation of where the industry is going. You can find all the recordings and links at the end of this blog post.&lt;/p&gt;

&lt;h2&gt;
  
  
  KubeCon Session
&lt;/h2&gt;

&lt;p&gt;KubeCon is the &lt;a href="https://www.cncf.io/blog/2020/09/23/kubecon-cloudnativecon-europe-2020-virtual-conference-transparency-report-a-very-successful-first-virtual-event/"&gt;largest conference&lt;/a&gt; where I’ve presented so far and it was a pleasure this time to present with &lt;a href="https://twitter.com/tracymiranda"&gt;Tracy Miranda&lt;/a&gt; (Executive Director of the &lt;a href="http://cd.foundation"&gt;CD Foundation&lt;/a&gt;). We focused the session on how &lt;a href="http://jenkins-x.io"&gt;Jenkins X&lt;/a&gt; and other projects like&lt;a href="http://zeebe.io"&gt;Zeebe&lt;/a&gt; are helping teams to accelerate while they are going to the Cloud.&lt;/p&gt;

&lt;p&gt;The presentation heavily relied on the &lt;a href="https://www.amazon.co.uk/Accelerate-Software-Performing-Technology-Organizations/dp/1942788339/ref=sr_1_1?adgrpid=105606882844&amp;amp;dchild=1&amp;amp;gclid=EAIaIQobChMIo-jQibuB7AIVBZ53Ch2Qxge9EAAYASAAEgLSXPD_BwE&amp;amp;hvadid=447114987736&amp;amp;hvdev=c&amp;amp;hvlocphy=9072502&amp;amp;hvnetw=g&amp;amp;hvqmt=e&amp;amp;hvrand=17004903559092500393&amp;amp;hvtargid=kwd-307609789829&amp;amp;hydadcr=18461_1772266&amp;amp;keywords=accelerate+book&amp;amp;qid=1600939151&amp;amp;sr=8-1&amp;amp;tag=googhydr-21"&gt;Accelerate book&lt;/a&gt; which describes all the practices that can boost your team’s productivity while building complex and distributed applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zNkkBHQj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/09/screenshot-2020-09-22-at-14.49.26.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zNkkBHQj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/09/screenshot-2020-09-22-at-14.49.26.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We got amazing feedback from the people joining the live stream and further discussions were started from there that made me believe that I need to keep working and expanding on the working examples for people to use as a reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring One Session
&lt;/h2&gt;

&lt;p&gt;This session was more focused on the Spring Ecosystem and the tools that Java Developers are using to build, package, and deploy their Cloud Native Applications on top of Kubernetes.&lt;/p&gt;

&lt;p&gt;It was really interesting to see how Pivotal/VMWare are going all in towards Kubernetes with their new iteration of &lt;a href="https://www.cloudfoundry.org/blog/cloud-foundry-becomes-more-kubernetes-native-with-cf-for-k8s/"&gt;Cloud Foundry for Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This presentation included examples inside the Demo Application on how to use &lt;a href="https://spring.io/projects/spring-cloud-gateway"&gt;Spring Cloud Gateway&lt;/a&gt;, &lt;a href="https://spring.io/projects/spring-cloud-contract"&gt;Consumer-Driven Contract Testing with Spring Cloud Contracts&lt;/a&gt; and how to add fallbacks and circuit breakers with &lt;a href="https://github.com/resilience4j/resilience4j"&gt;Resielience4J&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The goal for all these examples, is not to show how these projects work but how they were architected following Cloud Native patterns and Best Practices.&lt;/p&gt;

&lt;p&gt;The feedback and the number of live attendees were amazing (almost 1200 online viewers while I was doing the presentation) so I am looking forward to participating in this amazing conference in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links and References
&lt;/h2&gt;

&lt;p&gt;Check out the recordings and if you have any questions, comments, feedback, or if you want to help me to make the examples better, feel free to drop me a comment here or a DM in twitter &lt;a href="http://twitter.com/salaboy"&gt;@salaboy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://springone.io/2020/sessions/from-java-monoliths-to-k8s"&gt;https://springone.io/2020/sessions/from-java-monoliths-to-k8s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://springone.io/2020/sessions/from-java-monoliths-to-k8s"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dV6S9DDF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/09/screenshot-2020-09-11-at-11.22.14.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.slideshare.net/salaboy/kubecon-2020-eu-virtual-how-we-migrated-our-monolith-to-k8s"&gt;KubeCon 2020 EU Virtual: How we migrated our monolith to K8s&lt;/a&gt;&lt;/strong&gt; from &lt;strong&gt;&lt;a href="https://www.slideshare.net/salaboy"&gt;Mauricio (Salaboy) Salatino&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>bpmn2</category>
      <category>camunda</category>
      <category>cicd</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Jenkins X on Linode LKE Webinar</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Mon, 17 Aug 2020 07:27:26 +0000</pubDate>
      <link>https://dev.to/salaboy/jenkins-x-on-linode-lke-webinar-3g51</link>
      <guid>https://dev.to/salaboy/jenkins-x-on-linode-lke-webinar-3g51</guid>
      <description>&lt;p&gt;A couple of weeks ago, I did a webinar for &lt;a href="http://linode.com"&gt;Linode&lt;/a&gt; and their Managed Kubernetes Engine (as part of &lt;a href="http://learnk8s.io"&gt;LearnK8s&lt;/a&gt;) where I run &lt;a href="http://jenkins-x.io"&gt;Jenkins X&lt;/a&gt; and demonstrated the project capabilities. Here you can find my slides and the links to watch the webinar on-demand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.slideshare.net/salaboy/jenkins-x-on-linode-lke"&gt;Jenkins X on Linode LKE&lt;/a&gt;&lt;/strong&gt; from &lt;strong&gt;&lt;a href="https://www.slideshare.net/salaboy"&gt;Mauricio (Salaboy) Salatino&lt;/a&gt;&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Here you can also find a tutorial on how to get started with Jenkins X on Linode, which were the preparation steps that I followed to get Jenkins X ready for my webinar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linode.com/docs/kubernetes/how-to-deploy-jenkins-x-in-linode-kubernetes-engine/"&gt;https://www.linode.com/docs/kubernetes/how-to-deploy-jenkins-x-in-linode-kubernetes-engine/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, here is the link to watch the webinar recording on-demand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://event.on24.com/eventRegistration/EventLobbyServlet?target=reg20.jsp&amp;amp;partnerref=linkedinsocial&amp;amp;utm_content=Oktopost-linkedin&amp;amp;utm_medium=social&amp;amp;utm_source=linkedin&amp;amp;eventid=2455137&amp;amp;sessionid=1&amp;amp;key=505A2E08A3D786778378EDFBF77C0007&amp;amp;regTag=1210267&amp;amp;sourcepage=register"&gt;https://event.on24.com/eventRegistration/EventLobbyServlet?target=reg20.jsp&amp;amp;partnerref=linkedinsocial&amp;amp;utm_content=Oktopost-linkedin&amp;amp;utm_medium=social&amp;amp;utm_source=linkedin&amp;amp;eventid=2455137&amp;amp;sessionid=1&amp;amp;key=505A2E08A3D786778378EDFBF77C0007&amp;amp;regTag=1210267&amp;amp;sourcepage=register&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure you watch the KubeFlow webinar from my friend Salman which you can also choose from the previous link.&lt;/p&gt;

&lt;p&gt;Stay tuned and join me tomorrow at &lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/program/schedule/"&gt;@Kubecon&lt;/a&gt; where I will be showing more of &lt;a href="http://Jenkins-x.io"&gt;Jenkins X&lt;/a&gt; and &lt;a href="http://Zeebe.io"&gt;Zeebe&lt;/a&gt; to provide business visibility and microservices orchestration.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>cloud</category>
      <category>cloudnative</category>
      <category>community</category>
    </item>
    <item>
      <title>JNation 2020: From Monolith to K8s</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Tue, 02 Jun 2020 10:40:50 +0000</pubDate>
      <link>https://dev.to/salaboy/jnation-2020-from-monolith-to-k8s-3iom</link>
      <guid>https://dev.to/salaboy/jnation-2020-from-monolith-to-k8s-3iom</guid>
      <description>&lt;p&gt;I was really happy to participate in this online edition of &lt;a href="http://jnation.pt"&gt;JNation&lt;/a&gt;. I would have preferred to be presenting in Portugal, but the quality of other speakers and the content that was presented at the conference was amazing.&lt;/p&gt;

&lt;p&gt;During my presentation, I wanted to share pointers to tools and lessons learned while going from a big Java monolith to a more distributed approach. I touch quickly on two main concepts from DDD (Domain Driven Design) Bounded Contexts and Context Maps, without trying to define them too deeply but more to show some practical considerations derived from them while implementing real-life solutions. The presentation is heavily oriented to share insights on what to look at in certain situations, more than to dictate solutions.&lt;/p&gt;

&lt;p&gt;The conference is still live here: &lt;a href="https://2020.jnation.pt/schedule/"&gt;https://2020.jnation.pt/schedule/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Slides &amp;amp; Video
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.slideshare.net/salaboy/jnation-2020-from-monolithto-k8s?ref=https://salaboy.com/"&gt;https://www.slideshare.net/salaboy/jnation-2020-from-monolithto-k8s?ref=https://salaboy.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Video Link to be added when available&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Workshop Style Guide (work in progress, contributions are welcome): &lt;a href="https://github.com/salaboy/from-monolith-to-k8s"&gt;https://github.com/salaboy/from-monolith-to-k8s&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Repositories: &lt;a href="https://github.com/salaboy?tab=repositories&amp;amp;q=fmtok8s"&gt;https://github.com/salaboy?tab=repositories&amp;amp;q=fmtok8s&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Jenkins X: &lt;a href="http://jenkins-x.io"&gt;http://jenkins-x.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zeebe: &lt;a href="http://zeebe.io"&gt;http://zeebe.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;There were some questions about Saga Patterns, here are some links about what’s coming for Zeebe: 

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/berndruecker/orchestrate-aws-lambda-using-camunda-cloud-3nne-temp-slug-9350392"&gt;https://blog.bernd-ruecker.com/orchestrate-aws-lambda-using-camunda-cloud-8d27dc640f69&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What to expect being supported in Zeebe, already working in Camunda BPM: &lt;a href="https://blog.bernd-ruecker.com/saga-how-to-implement-complex-business-transactions-without-two-phase-commit-e00aa41a1b1b"&gt;https://blog.bernd-ruecker.com/saga-how-to-implement-complex-business-transactions-without-two-phase-commit-e00aa41a1b1b&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congrats to all the organisers for such an amazing experience!&lt;/p&gt;

&lt;p&gt;I look forward to the 2021 edition of &lt;a href="http://jnation.pt"&gt;JNation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>bpm</category>
      <category>bpmn2</category>
      <category>camunda</category>
    </item>
    <item>
      <title>Why isn’t Jenkins X’s future more Open?</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Tue, 19 May 2020 18:34:22 +0000</pubDate>
      <link>https://dev.to/salaboy/why-isn-t-jenkins-x-s-future-more-open-4mik</link>
      <guid>https://dev.to/salaboy/why-isn-t-jenkins-x-s-future-more-open-4mik</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;or as an alternative title: “How to kill a community project 101”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is quite common to see companies behind Open Source projects fighting to provide a sustainable business model that builds up on top of these community projects. I know because I worked as a core engineer and also contributed to projects like &lt;a href="https://jbpm.org/"&gt;jBPM&lt;/a&gt;, &lt;a href="http://drools.org/"&gt;Drools&lt;/a&gt;, &lt;a href="http://activiti.org/"&gt;Activiti&lt;/a&gt;, &lt;a href="https://spring.io/projects/spring-cloud"&gt;Spring Cloud&lt;/a&gt;, &lt;a href="http://jenkins-x.io/"&gt;Jenkins X&lt;/a&gt;, &lt;a href="https://www.jhipster.tech/"&gt;JHipster&lt;/a&gt;, &lt;a href="http://zeebe.io/"&gt;Zeebe&lt;/a&gt;, etc. and I’ve seen these situations arise from the inside.&lt;/p&gt;

&lt;p&gt;Finding the right commercial and Open Source balance isn’t always straightforward and it isn’t painless either. You might have heard of the stories of community engineers and teams arguing with “the company’s upper management“ to keep working on their open source project with their already open-source practices while the product is being built. Particularly after the team spent so much effort to nurture the right culture and collaboration with the community.&lt;/p&gt;

&lt;p&gt;More recently I’ve noticed the Jenkins X community project going down the same path &lt;a href="https://jenkins-x.io/blog/2020/05/15/helm3/"&gt;https://jenkins-x.io/blog/2020/05/15/helm3/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I decided to try to summarize the downsides of approaching building a product on top of an open-source project by killing its community. &lt;/p&gt;

&lt;h1&gt;
  
  
  A bit of background
&lt;/h1&gt;

&lt;p&gt;I’ve been involved with the Jenkins X initiative since the early beginning. Back in 2018, I delivered a workshop at JBCNConf about deploying distributed services using Jenkins X (&lt;a href="https://www.jbcnconf.com/2018/infoTalk.html?id=24"&gt;https://www.jbcnconf.com/2018/infoTalk.html?id=24&lt;/a&gt; / &lt;a href="https://docs.google.com/document/d/1kfSYhIuPa249poM8quyiazolOyn-feWPbVHyHmy5pD8/edit#heading=h.h38mzmjnh0xo"&gt;https://docs.google.com/document/d/1kfSYhIuPa249poM8quyiazolOyn-feWPbVHyHmy5pD8/edit#heading=h.h38mzmjnh0xo&lt;/a&gt;) and since then I’ve kept spreading the word and advocating its benefits.&lt;/p&gt;

&lt;p&gt;During this time the project owners and maintainers were always active in Slack and they kept an open and transparent way of running the project. What happened from 2018 until Jan of 2020 was remarkable, as the project grew a strong community of over 2500+ members in the Slack channel. Most of them were engaged in constructive discussions.&lt;/p&gt;

&lt;p&gt;In 2019 I was nominated as a temporary Steering Committee Member for the Jenkins X project &lt;a href="https://github.com/jenkins-x/jx-community/tree/master/committee-steering"&gt;https://github.com/jenkins-x/jx-community/tree/master/committee-steering&lt;/a&gt; . I was honored to be awarded such a position. In 2019, the &lt;a href="https://cd.foundation/"&gt;Continuous Delivery Foundation&lt;/a&gt; was created and Jenkins X joined as a founding member.&lt;/p&gt;

&lt;p&gt;Jenkins X is unlike any other project that I worked on in the past.&lt;/p&gt;

&lt;p&gt;Most of the project complexity comes from downstream projects that are glued together. The speed of changes in these projects is unprecedented and keeping up with all of it is a big challenge. Because of this, Jenkins X is more than a solution to a CI/CD problem, it is a shared community learning experience and a research project that pushes the boundaries of best practices for CI/CD in Kubernetes. &lt;/p&gt;

&lt;p&gt;In 2019, there was a lot of pressure to stabilize dependencies. The Jenkins X team and the community really came together to find solutions to continuous integration and continuous delivery challenges in a cloud-native way (the actual purpose of Jenkins X). Also in 2019, the Jenkins X core team expanded thanks to CloudBees (the company behind the project) which hired a lot of people working in the community. &lt;/p&gt;

&lt;p&gt;However, towards the end of 2019, the core engineering team began shifting its work to more private initiatives such as the SaaS offering of Jenkins X. As you would expect, the open-source project saw a slowdown.&lt;/p&gt;

&lt;p&gt;I thought “that’s normal and there is nothing to worry about.” The company behind the project has to make a profit at the end of the day. CloudBees also announced that the project was to take a more defined route and not all decisions would be taken in the open, including the new work on the innovation side (&lt;a href="https://jenkins-x.io/blog/2020/05/15/helm3/#why-isnt-this-all-more-open"&gt;https://jenkins-x.io/blog/2020/05/15/helm3/#why-isnt-this-all-more-open&lt;/a&gt;). It’s a tradeoff, of course. Cloudbees employees have more to say on the project and development might go faster in the short term, but you could lose the community engagement and contribution. What’s important is how you strike the balance.&lt;/p&gt;

&lt;h1&gt;
  
  
  What we lose
&lt;/h1&gt;

&lt;p&gt;When a popular Open Source project like Jenkins X decides to stop innovating in the open, you can expect a less engaged community and fewer core engineers looking after the project. The project might also lose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The strong sense of community&lt;/li&gt;
&lt;li&gt;The trust between core and community members &lt;/li&gt;
&lt;li&gt;The sustained pace and quality of work&lt;/li&gt;
&lt;li&gt;The drive to work together and solve challenges&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.theopensourceway.org/wiki/Communities_of_practice"&gt;Open Source way&lt;/a&gt; of working is no longer applied. Building, maintaining and growing a healthy community around it is hard, if not impossible&lt;/li&gt;
&lt;li&gt;The project loses its competitive edge&lt;/li&gt;
&lt;li&gt;The company’s appeal to new Open Source clients/users&lt;/li&gt;
&lt;li&gt;A transparent roadmap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine if Linus Torvalds, or even a multinational company like Red Hat would decide to roll out their own version of Linux in private: Linux++. The next thing you’ll see is thousand of upset contributors looking for alternatives and customers wondering if it is time to move on.&lt;/p&gt;

&lt;p&gt;I always wonder, “If you ask an Open Source project to stop working in a way that made your project popular, do you actually understand how Open Source works?”&lt;/p&gt;

&lt;h1&gt;
  
  
  What can be done about this?
&lt;/h1&gt;

&lt;p&gt;I’ve learned so many things from these last 2 years involved with the project that I think it is worth the time and effort to express my discomfort with their decision. Knowing personally the engineers behind the project, their careers, and their way of working, this is clearly a company’s decision to stop Open Source innovation in favor of product development. If you are part of the Jenkins X community, feel free to express your opinions about these changes in priorities and approaches and comments. &lt;/p&gt;

&lt;p&gt;I’ve just created the following GitHub issue &lt;a href="https://github.com/jenkins-x/jx/issues/7207"&gt;https://github.com/jenkins-x/jx/issues/7207&lt;/a&gt; for you to &lt;strong&gt;upvote&lt;/strong&gt; if you agree with the points covered in this blog post. As a community, we should express our concerns, so the company behind the project can see that doing things in the open matters.&lt;br&gt;&lt;br&gt;
If you want to get in touch, drop me a message via &lt;a href="http://twitter.com/salaboy"&gt;twitter&lt;/a&gt; or drop me a comment here.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>cloud</category>
      <category>cloudnative</category>
      <category>community</category>
    </item>
    <item>
      <title>Orchestrating Cloud Events with Zeebe</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Mon, 18 May 2020 07:58:55 +0000</pubDate>
      <link>https://dev.to/salaboy/orchestrating-cloud-events-with-zeebe-11pi</link>
      <guid>https://dev.to/salaboy/orchestrating-cloud-events-with-zeebe-11pi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: This blog post is about Cloud-Native software, containers, Cloud Events, and Workflows. It describes a concrete example that you can run yourself using &lt;a href="http://kubernetes.io"&gt;Kubernetes&lt;/a&gt;, &lt;a href="https://helm.sh"&gt;Helm&lt;/a&gt;, and &lt;a href="http://zeebe.io"&gt;Zeebe.io&lt;/a&gt;. You should be familiar with Kubernetes and Helm to follow along and will learn about &lt;a href="http://zeebe.io"&gt;zeebe.io&lt;/a&gt; and &lt;a href="http://cloudevents.io"&gt;cloudevents.io&lt;/a&gt; on your way.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While working with Kubernetes the chances are quite high that you’ll find services written in different languages and using different technologies stacks. CloudEvents (&lt;a href="http://cloudevents.io/"&gt;cloudevents.io&lt;/a&gt; / &lt;a href="https://github.com/cloudevents/spec"&gt;CNCF spec&lt;/a&gt;) was born to enable these systems to exchange information by describing their events in a standard way, no matter which transports these services are using (HTTP, Messaging AMPQ/JMS, Protobuf, etc). &lt;/p&gt;

&lt;p&gt;In such scenarios, where you have events being produced and consumed by different systems, there are common requirements that start to arise when the system grows larger, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visibility&lt;/strong&gt; : being able to see and understand event interactions from a business perspective.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coordination&lt;/strong&gt; : sometimes you just need to define and check that a certain sequence of events happened or are produced to meet certain goals. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt; : mechanisms to deal with problems if things are not going as expected, to make sure that we correct these situations and, from a business perspective, we keep track and continuously improve how we operate. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance&lt;/strong&gt; : enforcing certain rules and orders between these events to make sure that regulations are being met. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To tackle such requirements without reinventing the wheel you can use a Workflow Engine which provides very flexible solutions for these common sets of requirements. In this blog post, I cover &lt;a href="http://zeebe.io"&gt;Zeebe&lt;/a&gt;, a Cloud Native Workflow Engine, and how you can consume and emit Cloud Events from a Workflow. &lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let’s imagine that we have two services to deal with customers wanting to buy tickets for music concerts on our website. Most of these systems are required to handle high loads when a new concert goes online, as fans might want to buy all the tickets in a short period of time. &lt;/p&gt;

&lt;p&gt;The website and customer flow look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oLrwiepl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/tickets-flow-ui.png%3Fw%3D745" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oLrwiepl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/tickets-flow-ui.png%3Fw%3D745" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the backend, there will be a service in charge of queuing customers that want to buy tickets and a payment service in charge of processing the payments. Due to the high demand, timeouts need to be in place to make sure that customers that are not willing to buy the tickets get removed from the queue if they spend too much time deciding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jM2dG8Tc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/cloud-events-concerts-blog-post.png%3Fw%3D903" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jM2dG8Tc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/cloud-events-concerts-blog-post.png%3Fw%3D903" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These two services have been designed with an &lt;em&gt;Event-Driven Architecture&lt;/em&gt; in mind, so they emit events and react to events. The following events are consumed and emitted by the &lt;strong&gt;TicketsService&lt;/strong&gt; : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Tickets.CustomerQueueJoined:&lt;/em&gt;&lt;/strong&gt; A customer is interested in buying a ticket so they have joined the queue to buy tickets &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Tickets.Requested&lt;/em&gt;&lt;/strong&gt;** :**  A customer has selected one or more tickets for the concert and is ready to checkout. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Tickets.CheckedOut:&lt;/em&gt;&lt;/strong&gt; A checkout action was confirmed by the customer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Tickets.Emitted:&lt;/em&gt;&lt;/strong&gt; the tickets have been emitted to the customer. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Notifications.Requested&lt;/em&gt;&lt;/strong&gt;** :** A notification was sent to the customer. In our example, this can happen due to time outs while checking out the tickets or due time out from the payment service while authorizing the payment. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the other hand, the &lt;strong&gt;PaymentService&lt;/strong&gt; can react and emit the following events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Payments.RequestReceived:&lt;/em&gt;&lt;/strong&gt; A payment request has been received and it is queued to be processed. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;Payments.Authorized:&lt;/em&gt;&lt;/strong&gt; The payment was successfully processed and authorized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By looking at these events you can quickly realize that the interactions between these services and the Customer on the website are asynchronous. Events are emitted and some other service will react and process them, probably emitting another event as a result.&lt;br&gt;&lt;br&gt;
In the following sections, an Orchestration approach is introduced without changing our service, and we can tackle the points mentioned in the introduction ( &lt;strong&gt;Visibility, Coordination, Error Handling, Compliance&lt;/strong&gt; ) &lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Orchestration Approach
&lt;/h2&gt;

&lt;p&gt;Workflow Engines were designed to orchestrate services and people together providing visibility and audit logs for how the work is being done. These engines work by automating (running) models that represent these &lt;em&gt;service-to-service&lt;/em&gt; and &lt;em&gt;service-to-people&lt;/em&gt; interactions. These models provide a graphical representation that can be understood not only by technical people but by every person inside the company. Workflow Engines help us to make sure that the services being orchestrated don’t need to know about each other, which makes our services decoupled and independent. &lt;/p&gt;

&lt;p&gt;If we add CloudEvents to the picture, the workflow engine will emit and consume cloud events itself and can then enforce certain rules about their sequence. A workflow engine will also provide out-of-the-box visibility to all these interactions and automatic data aggregation to understand how our systems are working together from a  business perspective. &lt;/p&gt;

&lt;p&gt;A well understood and industry-wide used modeling language is BPMN by the &lt;a href="https://www.omg.org/"&gt;OMG&lt;/a&gt;. A workflow model in BPMN will look like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b8cqJDvx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/tickets-workflow.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b8cqJDvx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/tickets-workflow.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This diagram is not imposing any runtime constraints about where the Services should be or how to interact with them, it is only defining what the sequence of these events should be and, for example, when to emit certain events. Both the Tickets Service and the Payments Service can be running in the Cloud, On-Prem, with or without containers. Zeebe can orchestrate these events to make sure that ticket purchase events are tracked correctly.  &lt;/p&gt;

&lt;p&gt;It is important to recognize the flexibility and features provided by BPMN in this very simple example. Out-of-the-box with BPMN we can use Timer Boundary events to define time outs for receiving Cloud Events as well as do Error Handling in case things go wrong. BPMN can do much more than what is shown in this example, for example, split the flow based on conditions, do tasks in parallel, more complex error handling, etc. &lt;a href="https://camunda.com/bpmn/"&gt;You can find more about BPMN here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
You can find the BPMN models used in this blog post and some other examples here: &lt;a href="https://github.com/salaboy/zeebe-cloud-events-examples"&gt;https://github.com/salaboy/zeebe-cloud-events-examples&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Architecture&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By using a Cloud-Native Workflow Engine like &lt;a href="https://zeebe.io/"&gt;Zeebe&lt;/a&gt;, we can define this flow of events with a simple BPMN Diagram that allows us to express quite complicated scenarios in a graphical way. &lt;/p&gt;

&lt;p&gt;Zeebe, the workflow orchestrator, is pretty flexible in supporting different deployment scenarios. It can be installed into your local environment using Docker Compose, run on &lt;a href="http://helm.zeebe.io/"&gt;Kubernetes using Helm&lt;/a&gt;, or you can leverage &lt;a href="https://camunda.com/products/cloud/"&gt;Camunda Cloud&lt;/a&gt; which gives you an installation-free and managed Zeebe Cluster instance. &lt;/p&gt;

&lt;p&gt;To enable Zeebe to consume and emit Cloud Events, you will need the  &lt;a href="https://github.com/zeebe-io/zeebe-cloud-events-router"&gt;Zeebe Cloud Events Router&lt;/a&gt;, which can map BPMN Events and Commands to Cloud Events which are understood by the existing services. This is a bidirectional router, as it is in charge of translating events that are generated outside the orchestrator scope (outside Zeebe) and emitting events that are meant for Domain-Specific Services. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dbc3-_Z4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/tickets-booking-cloud-events.png%3Fw%3D1002" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dbc3-_Z4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/tickets-booking-cloud-events.png%3Fw%3D1002" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cloud Events could be transported via various protocols, e.g. Kafka, WebSockets or HTTP. This blog post focuses on HTTP, in future posts you will see how these HTTP Cloud Event endpoints can be integrated with services that use other transports.&lt;/p&gt;

&lt;p&gt;The Zeebe Cloud Events Router exposes a set of HTTP endpoints to receive external Cloud Events:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;/ POST&lt;/strong&gt; -&amp;gt; receive a Cloud Event that will be mapped to a Job Completion, which will make the task to move forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/jobs GET&lt;/strong&gt; -&amp;gt; Get a list of Pending Jobs to be completed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/message POST&lt;/strong&gt; -&amp;gt; Receive a Cloud Event that will be mapped to a BPMN Message&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/workflow POST&lt;/strong&gt; -&amp;gt; Receive a Cloud Event that will be mapped to Start a Workflow Instance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/workflows POST&lt;/strong&gt; -&amp;gt; Create a mapping between a Cloud Event Type and a Workflow Key, so we can start a new Workflow Instance with a Cloud Event&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/workflows GET&lt;/strong&gt; -&amp;gt; Get all available Cloud Events to Workflow Mappings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can always access the Open API UI in the Router by pointing your browser to &lt;a href="http://localhost:8080/swagger-ui.html"&gt;http://:/swagger-ui.html&lt;/a&gt; for a more interactive list of the REST endpoints provided by the Zeebe Cloud Events Router.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cloud Events Mappings
&lt;/h3&gt;

&lt;p&gt;There are three patterns supported in BPMN workflows::&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1# EMIT_ONLY&lt;/strong&gt; , meaning that you want to emit a Cloud Event and move forward. We can always catch/consume another event later in the workflow, for example:&lt;/p&gt;

&lt;p&gt;1-A) &lt;strong&gt;Emit&lt;/strong&gt; and catch Cloud Event with a &lt;strong&gt;BPMN Intermediate Catch Event&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2VwKJj83--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/emit-only.png%3Fw%3D818" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2VwKJj83--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/emit-only.png%3Fw%3D818" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1-B) &lt;strong&gt;Emit&lt;/strong&gt; and catch Cloud Event with a &lt;strong&gt;BPMN&lt;/strong&gt;  &lt;strong&gt;Receive Task.&lt;/strong&gt; As we will see in the following example, using a Receive Task enables use to use Boundary Events.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---cAUCq2m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/emit-only-receive-task.png%3Fw%3D996" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---cAUCq2m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/emit-only-receive-task.png%3Fw%3D996" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#2 WAIT_FOR_CLOUD_EVENT&lt;/strong&gt; emit and wait for a Cloud Event to continue inside a &lt;strong&gt;BPMN Service Task&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DQUUpdGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/wait-for-cloud-event.png%3Fw%3D756" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DQUUpdGK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/wait-for-cloud-event.png%3Fw%3D756" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;#3 Start a Workflow Instance&lt;/strong&gt; by sending a Cloud Event&lt;/p&gt;

&lt;p&gt;The first approach ( &lt;strong&gt;EMIT_ONLY&lt;/strong&gt; ) can be used when you want to use a &lt;strong&gt;&lt;em&gt;BPMN&lt;/em&gt;&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;Service Task&lt;/em&gt;&lt;/strong&gt; to Emit a Cloud Event, usually to delegate the logic to a third party service and it doesn’t need to wait for an incoming event to complete. An incoming event can be mapped by using a &lt;strong&gt;&lt;em&gt;BPMN&lt;/em&gt;&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;Intermediate Catch Event&lt;/em&gt;&lt;/strong&gt; or a &lt;strong&gt;&lt;em&gt;BPMN&lt;/em&gt;&lt;/strong&gt;  &lt;strong&gt;&lt;em&gt;Receive Task&lt;/em&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The second approach ( &lt;strong&gt;WAIT_FOR_CLOUD_EVENT&lt;/strong&gt; ) allows you to map two Cloud Events to the same &lt;strong&gt;&lt;em&gt;BPMN Service Task&lt;/em&gt;&lt;/strong&gt;. The first Cloud Event will be the one that is emitted and the second one will define when to complete the &lt;strong&gt;&lt;em&gt;Service Task&lt;/em&gt;&lt;/strong&gt;. This is usually to map a service that reacts to an event and, when finished processing, emits one. &lt;/p&gt;

&lt;p&gt;A third ( &lt;strong&gt;Start Workflow Instance&lt;/strong&gt; ) pattern can be considered the mapping between a Cloud Event and the action of starting a Workflow Instance. For this pattern, you will need to map which &lt;strong&gt;&lt;em&gt;Cloud Event&lt;/em&gt;&lt;/strong&gt; can trigger the creation of new Workflow Instances. &lt;/p&gt;

&lt;p&gt;The following example uses these three patterns to illustrate how to emit and consume Cloud Events from a BPMN Workflow. &lt;a href="https://github.com/salaboy/zeebe-cloud-events-examples/blob/master/tickets.bpmn"&gt;You can find the BPMN model here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For example, if we want to emit a Cloud Event, the Queue To Request Tickets Service Task defines the following properties and headers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G06Qiv9o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/queuetorequest-props.png%3Fw%3D852" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G06Qiv9o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/queuetorequest-props.png%3Fw%3D852" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wlo72TrY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/queuetorequest-st-headers-2.png%3Fw%3D850" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wlo72TrY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/queuetorequest-st-headers-2.png%3Fw%3D850" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zVeftoMY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/queuetorequest-st-1.png%3Fw%3D292" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zVeftoMY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/queuetorequest-st-1.png%3Fw%3D292" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see there is one important property and 3 headers being defined:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ServiceTask.Type&lt;/strong&gt; = “cloudevents”, this delegates the work to our Zeebe Cloud Events Router. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header Mode&lt;/strong&gt; = EMIT_ONLY defines the behavior, for this mode, a Cloud Event will be emitted &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header Type&lt;/strong&gt; = “Tickets.CustomerQueueJoined” defines the type of Cloud Event that will be emitted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header Host&lt;/strong&gt; = “” this is where the Cloud Event will be emitted to. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is important to note that the data of the Cloud Event created will contain all the workflow variables with their current value. &lt;/p&gt;

&lt;p&gt;The example also shows how to emit and consume different Cloud Events from the same Service Task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8ptTzqLo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/checkout-st-headers.png%3Fw%3D852" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8ptTzqLo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/checkout-st-headers.png%3Fw%3D852" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qNNW8lrF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/checkout-st.png%3Fw%3D328" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qNNW8lrF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/checkout-st.png%3Fw%3D328" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this mode, the Service Task will wait for a Cloud Event of type “ &lt;strong&gt;Payments.RequestReceived&lt;/strong&gt; ” to complete.&lt;/p&gt;
&lt;h2&gt;
  
  
  Running the Example
&lt;/h2&gt;

&lt;p&gt;There is a Java Spring Boot implementation of this example available here: &lt;a href="https://github.com/salaboy/zeebe-cloud-events-examples"&gt;https://github.com/salaboy/zeebe-cloud-events-examples&lt;/a&gt;. There are several ways of running this example (starting all the services locally in your laptop, docker, dockercompose, Kubernetes). We will take a look at two of these options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running in your own Kubernetes Cluster with Helm&lt;/li&gt;
&lt;li&gt;Running with Camunda Cloud&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to run the example you will need the following components: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://zeebe.io/"&gt;Zeebe&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Zeebe Cloud Events Router&lt;/li&gt;
&lt;li&gt;Tickets Service&lt;/li&gt;
&lt;li&gt;Payment Service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The example, for the sake of simplicity, uses only HTTP transport, but it can be easily expanded to use other transports such as WebSockets and Kafka. &lt;/p&gt;
&lt;h3&gt;
  
  
  Running in your own Kubernetes Cluster with Helm
&lt;/h3&gt;

&lt;p&gt;Because we are building Cloud-Native Applications, we will install these services in a Kubernetes Cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MXJhEt21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/your-infrastructure.png%3Fw%3D490" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MXJhEt21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/your-infrastructure.png%3Fw%3D490" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can leverage Helm to install a  Zeebe Cluster including Operate into your Kubernetes cluster:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;helm repo add zeebe &lt;a href="http://helm.zeebe.io"&gt;http://helm.zeebe.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;helm install my-zeebe zeebe/zeebe-full&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then we can install the Zeebe Cloud Events Router:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;helm install router –set env.ZEEBE_CLIENT_BROKER_CONTACTPOINT=my-zeebe-zeebe-gateway:26500 zeebe/zeebe-cloud-events-router&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice that we are pointing the Zeebe Cloud Events Router to our Zeebe Cluster Gateway address. &lt;/p&gt;

&lt;p&gt;And finally, we install the Tickets and Payment Services:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;helm install –set env.ZEEBE_CLOUD_EVENTS_ROUTER=&lt;a href="http://zeebe-cloud-events-router"&gt;http://zeebe-cloud-events-router&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;tickets zeebe/tickets-service&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;helm install –set env.ZEEBE_CLOUD_EVENTS_ROUTER=&lt;a href="http://zeebe-cloud-events-router"&gt;http://zeebe-cloud-events-router&lt;/a&gt; payments zeebe/payments-service&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice how both services are referencing the Zeebe Cloud Events router to be able to interact with it. &lt;/p&gt;

&lt;p&gt;In order to interact with Operate, the Zeebe Cluster and the Cloud Events Router inside your cluster you can use &lt;code&gt;kubectl port-foward&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl port-forward svc/my-zeebe-zeebe-gateway 26500:26500&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can run for example &lt;code&gt;zbctl status –insecure&lt;/code&gt; from your terminal to check the Zeebe Cluster Topology and Status. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl port-forward svc/zeebe-cloud-events-router 8085:80&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can interact with the Zeebe Cloud Events Router in your localhost:8085 address. Later you will send HTTP requests to some of these endpoints using curl from your terminal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl port-forward svc/my-zeebe-operate  8081:80&lt;br&gt;&lt;br&gt;
Now you can point your browser to &lt;a href="http://localhost:8081/"&gt;http://localhost:8081&lt;/a&gt; and use Operate to see which workflows are available and how many executions do you have in your environment. &lt;strong&gt;&lt;em&gt;User: demo, Password: demo&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o6BD5jXN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-operate-dashboard.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o6BD5jXN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-operate-dashboard.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can deploy the Tickets Workflow, which can be found in this repository: &lt;a href="https://github.com/salaboy/zeebe-cloud-events-examples"&gt;https://github.com/salaboy/zeebe-cloud-events-examples&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;zbctl deploy tickets.bpmn –insecure&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "key": 2251799813685505,
  "workflows": [
    {
      "bpmnProcessId": "TICKETS",
      "version": 1,
      "workflowKey": 2251799813685504,
      "resourceName": "tickets.bpmn"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to register a Cloud Event to start a new workflow instance, you need to register this mapping into the Zeebe Cloud Events Router, which associates a Cloud Event to a Workflow Key: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&amp;gt;&lt;/strong&gt; curl -X POST &lt;a href="http://localhost:8085/workflows"&gt;http://localhost:8085/workflows&lt;/a&gt; -H “Content-Type: application/json” -d ‘{“cloudEventType” : “ &lt;strong&gt;&lt;em&gt;Tickets.Purchase&lt;/em&gt;&lt;/strong&gt; “, “bpmnProcessId” : “ &lt;strong&gt;TICKETS&lt;/strong&gt; “}’&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can start a workflow by emitting a Cloud Event “ &lt;strong&gt;Tickets.Purchase&lt;/strong&gt; ” to start a workflow:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;curl -X POST &lt;a href="http://localhost:8085/workflow"&gt;http://localhost:8085/workflow&lt;/a&gt; -H “Content-Type: application/json” -H “Ce-Id: ABC-123” -H “Ce-Type: &lt;strong&gt;&lt;em&gt;Tickets.Purchase&lt;/em&gt;&lt;/strong&gt; ” -H “Ce-Source: curl” -d ‘{“sessionId”:”1″ }’&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;In Operate you will see the token moving forward until the workflow complete.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1i82QdWE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-operate-flow.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1i82QdWE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-operate-flow.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the example with Camunda Cloud
&lt;/h3&gt;

&lt;p&gt;Now if you want to make your life easier, you can run Zeebe in Camunda Cloud, which is a managed service for Zeebe offered by Camunda. In this case, you only need to operate your services, and the Zeebe Cloud Events Router yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Hc4oKDJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-cloud.png%3Fw%3D633" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Hc4oKDJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-cloud.png%3Fw%3D633" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After signing up for an account in &lt;a href="https://accounts.cloud.camunda.io/signup"&gt;Camunda Cloud(Beta)&lt;/a&gt; you can create a Zeebe cluster in self-service. I’ve created one called &lt;strong&gt;&lt;em&gt;CloudEvents&lt;/em&gt;&lt;/strong&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BpphEPLT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/cloud-cluster.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BpphEPLT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/cloud-cluster.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Getting my cluster up and running took me less than 5 minutes. And as you can see you also have  Camunda Operate installed.&lt;/p&gt;

&lt;p&gt;You can now interact with this new Development Cluster by using &lt;code&gt;zbctl&lt;/code&gt; as we did in the previous section, but instead of using &lt;code&gt;kubectl port-forward&lt;/code&gt; you can now export your credentials as environment variables to allow &lt;code&gt;zbctl&lt;/code&gt; to connect with the remote cluster. If you scroll down in your Camunda Cloud Console, you will see the export commands that you can copy and paste into your terminal. Once this is done, you can deploy your workflow definition to the remote cluster using the same command as we did before: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Remember that you can find the BPMN models in this repository: &lt;a href="https://github.com/salaboy/zeebe-cloud-events-examples"&gt;https://github.com/salaboy/zeebe-cloud-events-examples&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;zbctl deploy tickets.bpmn&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice that now we are using SSL so there is no need for the &lt;code&gt;–insecure&lt;/code&gt; flag. &lt;/p&gt;


&lt;/blockquote&gt;

&lt;p&gt;For running the Zeebe Cloud Events Router against  a Zeebe Cluster in Camunda Cloud you just need to make sure that the Zeebe Cloud Events Router can connect to the Zeebe Cluster, and you do that by sending the following variables when you install the Zeebe Cloud Events Router with Helm:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;helm install router –set env.ZEEBE_CLIENT_BROKER_CONTACTPOINT=7ece08ec-f0df-43e4-ada6-55f46368ef64.zeebe.camunda.io:443 –set env.ZEEBE_CLIENT_ID=KChsFczamyQ604uGlCHployFmcavMo3n –set env.ZEEBE_CLIENT_SECRET= –set env.ZEEBE_AUTHORIZATION_SERVER_URL=&lt;a href="https://login.cloud.camunda.io/oauth/token"&gt;https://login.cloud.camunda.io/oauth/token&lt;/a&gt; –set env.ZEEBE_CLIENT_SECURITY_PLAINTEXT=false zeebe/zeebe-cloud-events-router&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Notice that you can obtain  from the Camunda Cloud Console, as you did for the terminal, this secret is needed to establish the connection over SSL. &lt;/p&gt;

&lt;p&gt;Once the Zeebe Cloud Events Router is running you can start new Workflow Instances in the same way as we did before.&lt;/p&gt;

&lt;p&gt;Register a Cloud Event to Start new Workflow Instances, you do this mapping into the Zeebe Cloud Events Router by associating a Cloud Event to a Workflow Key: &lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;curl -X POST &lt;a href="http://localhost:8085/workflows"&gt;http://localhost:8085/workflows&lt;/a&gt; -H “Content-Type: application/json” -d ‘{“cloudEventType” : “ &lt;strong&gt;&lt;em&gt;Tickets.Purchase&lt;/em&gt;&lt;/strong&gt; “, “bpmnProcessId” : “ &lt;strong&gt;&lt;em&gt;TICKETS&lt;/em&gt;&lt;/strong&gt; “}’&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Now you can start a workflow by emitting a Cloud Event “ &lt;strong&gt;Tickets.Purchase&lt;/strong&gt; ” to start a workflow:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;curl -X POST &lt;a href="http://localhost:8085/workflow"&gt;http://localhost:8085/workflow&lt;/a&gt; -H “Content-Type: application/json” -H “Ce-Id: ABC-123” -H “Ce-Type: &lt;strong&gt;&lt;em&gt;Tickets.Purchase&lt;/em&gt;&lt;/strong&gt; ” -H “Ce-Source: curl” -d ‘{“sessionId”:”1″ }&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;Notice that now, the execution of this workflow will be happening inside Camunda Cloud. This means that you can monitor these executions in the Camunda Operate hosted right beside your cluster:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GnxYPxOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-operate-inspect-instance.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GnxYPxOs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/05/camunda-operate-inspect-instance.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Sum up
&lt;/h1&gt;

&lt;p&gt;This blog post covers a basic example of how you can orchestrate Cloud Events using Zeebe Workflow. You saw how you can run all the components in your own Kubernetes Cluster as well as using Zeebe inside Camunda Cloud to avoid installing, running, and maintaining Zeebe in your infrastructure (one less thing to worry about!).&lt;/p&gt;

&lt;p&gt;This example shows how you can leverage a Workflow Engine (like Zeebe) and the BPMN language to orchestrate Cloud Events to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gain visibility and business traceability about how your services are interacting, where the bottle necks are and how to identify changes for continuous improvement.&lt;/li&gt;
&lt;li&gt;Have an orchestration layer for your Event Based systems. Having the right balance between orchestration and choreography is key to develop a robust system that can continuously evolve.&lt;/li&gt;
&lt;li&gt;Have a robust set of mechanisms to deal with exceptions and non-happy paths, such as time outs and business error handling.&lt;/li&gt;
&lt;li&gt;Make sure that events follow a natural order to fulfil a business objective, this is very useful to identify if the flow can be improved and to understand new business requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are other ways to run the example, for example using Docker Compose or even running the services outside of Kubernetes and locally on your laptop. Feel free to reach out (comment here or via &lt;a href="http://twitter.com/salaboy"&gt;twitter&lt;/a&gt;) if you have any questions about this.&lt;/p&gt;

&lt;p&gt;On a future blog post, a more advanced example will be covered using Knative, Cloud Events, Kafka, and WebSockets. &lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

</description>
      <category>workflow</category>
      <category>cloudevents</category>
      <category>cloud</category>
      <category>orchestration</category>
    </item>
    <item>
      <title>Lessons Learned: Offline Time / Holidays</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Tue, 24 Mar 2020 15:52:26 +0000</pubDate>
      <link>https://dev.to/salaboy/lessons-learned-offline-time-holidays-4n3j</link>
      <guid>https://dev.to/salaboy/lessons-learned-offline-time-holidays-4n3j</guid>
      <description>&lt;p&gt;I just came back from holidays in Cuba, it was an amazing experience (including rushing back due to COVID-19) but I’ve learned some valuable lessons from being completely offline for at least 9 days. Internet access was limited, to say the least, usually restricted to hotel lobbies and paid by the hour. Because I really needed some holidays I was avoiding getting online as much as I could so the environment was perfect for that.&lt;/p&gt;

&lt;p&gt;Some interesting things that I’ve learnt from this experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After 3 days of being offline, you don’t miss it anymore, and you start caring less about going online again. &lt;/li&gt;
&lt;li&gt;After 3 days of being offline, creativity starts to kick in again, I found myself writing a lot of interesting ideas about tech and other stuff that I am interested in. This is something that I find hard to do after a normal day of work. &lt;/li&gt;
&lt;li&gt;Being offline allows you to step back and reprioritize with an external point of view. This is very productive when you need to balance between things such as conferences, coding, initiatives, networking with different groups, etc. Stepping back from the day to day helps you to have a clear view of how important each of these things is and how they will impact your productivity and life/work balance. &lt;/li&gt;
&lt;li&gt;Being offline and isolated even for a week allows you to have a fresh perspective on the really important things that will not change. It was quite fascinating to see how fast companies are changing nowadays and how if you just miss a week &lt;/li&gt;
&lt;li&gt;I’ve learned about &lt;strong&gt;&lt;em&gt;“Screen Time -&amp;gt; Downtime” in iOS&lt;/em&gt;&lt;/strong&gt; to automatically block apps, which I set to From 20:00 to 7:30 every day. So now that I get back online I control myself with some time off. &lt;/li&gt;
&lt;li&gt;I’ve reminded myself of having at least a couple pet projects, those projects that you just do for fun. In my career, pet projects have been a source of inspiration and learning.
&lt;/li&gt;
&lt;li&gt;The power of Open Source and how it affects my priorities. I ended up realizing that priorities were easy to set if the focus is made on the open-source aspect of each project/initiative. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having loads of ideas and some inspiration from &lt;a href="https://www.jordanmechner.com/"&gt;Jordan Mechner&lt;/a&gt;‘s books pushed me to have now a dairy (with daily entries) full of potential pet projects and reminders about what things are important.&lt;/p&gt;

&lt;p&gt;I know.. this is not a tech blog post, but it might help someone else out there to share their experiences around their time off / holidays preferences.&lt;/p&gt;

&lt;p&gt;Stay tuned! more tech blog post are coming!&lt;/p&gt;

</description>
      <category>english</category>
      <category>java</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why is the @ljcjug awesome?</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Mon, 24 Feb 2020 15:57:48 +0000</pubDate>
      <link>https://dev.to/salaboy/why-is-the-ljcjug-awesome-jk</link>
      <guid>https://dev.to/salaboy/why-is-the-ljcjug-awesome-jk</guid>
      <description>&lt;p&gt;Last week I had the pleasure to talk with my friend Ryan Dawson from Seldon.io at the &lt;a href="https://www.meetup.com/Londonjavacommunity/events/268235299/?rv=co1&amp;amp;_xtd=gatlbWFpbF9jbGlja9oAJDE4MjM2MDM2LTVjNTEtNDNlZC04OTQ0LTNjOTk1MzZmMWRjYg"&gt;London Java Community meetup&lt;/a&gt;, which was hosted at the Birkbeck University here in London.&lt;/p&gt;

&lt;p&gt;The main topic of the evening was GoLang and our personal experiences as Java Developers while working on some projects with a different language, the toolchain, and how bad it feels when we are out of our comfort zone.&lt;/p&gt;

&lt;p&gt;I was surprised by the audience interaction, as we were not alone, others in the community has experienced the same pains with other languages and our presentations quickly became more like an open debate with several members of the group sharing their experiences and their opinions.&lt;/p&gt;

&lt;p&gt;The value of these groups is directly proportional to the group interaction and how much each member gets out of the meetup and it really felt like we all won/learned something that night. We had both students and professors from the university present in the room and even if some bits of our presentations were too advanced for them, they came up with very good questions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.meetup.com/Londonjavacommunity/"&gt;LJC&lt;/a&gt; is awesome because the people that show up really care about what they do and they have strong opinions, they are not shy to share them and the setup allows everyone to express their opinions in a safe environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Slides
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Java to GoLang by Ryan Dawson&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zeebe Operator, a practical use case for GoLang in Kubernetes Land&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Java vs Challengers&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Zeebe Operator Source Code: &lt;a href="https://github.com/zeebe-io/zeebe-operator"&gt;https://github.com/zeebe-io/zeebe-operator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zeebe Operator introduction: &lt;a href="https://dev.to/salaboy/zeebe-kubernetes-operator-4k0e"&gt;https://salaboy.com/2019/12/20/zeebe-kubernetes-operator/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Microservices Orchestration with &lt;a href="http://zeebe.io"&gt;Zeebe.io&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/salaboy/getting-started-with-knative-2020-994"&gt;Getting Started with Knative Blog Post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>camunda</category>
      <category>cloud</category>
      <category>cloudnative</category>
      <category>community</category>
    </item>
    <item>
      <title>Getting Started with Knative 2020</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Thu, 20 Feb 2020 12:09:48 +0000</pubDate>
      <link>https://dev.to/salaboy/getting-started-with-knative-2020-994</link>
      <guid>https://dev.to/salaboy/getting-started-with-knative-2020-994</guid>
      <description>&lt;p&gt;The &lt;a href="http://knative.dev"&gt;Knative project&lt;/a&gt; offers a set of components to build cloud-native applications on top of Kubernetes. These components offer higher-level abstractions enabling developers to focus on their actual services instead of all the boilerplate required to deploy their applications in Kubernetes.&lt;/p&gt;

&lt;p&gt;This blog post is all about getting started with Knative as fast as possible so you can experiment with Knative features by getting your hands dirty. Unfortunately, you will realize rather soon that Knative has a steep learning curve. This is not due to Knative concepts and it is directly related to the tech stack on which it is built.&lt;/p&gt;

&lt;p&gt;The main reason why I’ve created this blog post is to make sure that Java developers like myself can install and understand the basics of Knative with simple examples, so I can provide more advanced blog posts on how the Zeebe ( &lt;a href="http://zeebe.io"&gt;http://zeebe.io&lt;/a&gt; ) Knative integration will work, the main reasons behind it and how you can take advantage of it.&lt;/p&gt;

&lt;p&gt;In this blog post you will learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to get started with Knative in your own cluster&lt;/li&gt;
&lt;li&gt;How to deploy and interact with a simple Knative Service with an HTTP endpoint,&lt;/li&gt;
&lt;li&gt;Send/Receive CloudEvents using HTTP transport&lt;/li&gt;
&lt;li&gt;Write a Spring Boot + Spring Cloud Streams applications that communicate sending Cloud Events using Kafka&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Installing Knative with Gloo
&lt;/h1&gt;

&lt;p&gt;There are several ways to install Knative and most of them depend on Istio. In this blog post, I chose to use &lt;code&gt;glooctl&lt;/code&gt; for simplicity and leveraging the fact that it uses fewer resources. &lt;code&gt;glooctl&lt;/code&gt; replaces Istio with Gloo which is a lightweight ingress controller and provides all the features required by Knative. Alternatively, you can install Knative from the project official documentation: &lt;a href="https://knative.dev/docs/install/"&gt;https://knative.dev/docs/install/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find the full instructions here: &lt;a href="https://docs.solo.io/gloo/latest/installation/knative/"&gt;https://docs.solo.io/gloo/latest/installation/knative/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are running on Mac OSX you can install &lt;code&gt;glooctl&lt;/code&gt; with brew:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;brew install solo-io/tap/glooctl&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you have &lt;code&gt;glooctl&lt;/code&gt; and a Kubernetes Cluster up and running and reachable with &lt;code&gt;kubectl&lt;/code&gt;, you can install Knative Serving and Eventing 0.12.0 with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;glooctl install knative -g -e –install-knative-version=0.12.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once Knative is installed, we need to install Gloo as an API Gateway to route traffic from outside the cluster to our Knative workloads. We do this by using their Helm charts:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;helm repo add gloo &lt;a href="https://storage.googleapis.com/solo-public-helm"&gt;https://storage.googleapis.com/solo-public-helm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;helm repo update&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s create a new namespace for Gloo and install the Helm chart in there:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl create namespace gloo-system&lt;/p&gt;

&lt;p&gt;helm install gloo gloo/gloo –namespace gloo-system -f values.yaml&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Where the values file that I am using looks like this&lt;/p&gt;

&lt;p&gt;&lt;code&gt;values.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gateway: 
  enabled: false 
  settings: 
    integrations: 
      knative: 
        enabled: true 
        version: 0.12.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this, you now have Gloo ingress controller and Knative Serving and Eventing up and running.&lt;/p&gt;

&lt;p&gt;The files listed here and in the other sections can be found in this GitHub repository: &lt;a href="https://github.com/salaboy/knative-getting-started-java-resources"&gt;https://github.com/salaboy/knative-getting-started-java-resources&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What did I just install?
&lt;/h1&gt;

&lt;p&gt;We just installed &lt;a href="https://knative.dev/docs/serving/"&gt;Knative Serving&lt;/a&gt; and &lt;a href="https://knative.dev/docs/eventing/"&gt;Knative Eventing&lt;/a&gt; into our Kubernetes Cluster.&lt;/p&gt;

&lt;p&gt;Knative Serving provides an abstraction layer on top of Kubernetes Services Deployments and Ingress.&lt;/p&gt;

&lt;p&gt;Knative Serving is usually mentioned when people talk about Serverless on top of Kubernetes, as it provides Zero Downscale features out of the box for our applications, something that can’t be achieved with plain Kubernetes. The main concept in Knative Serving is a Knative Service. Initially, I was totally confused with the naming choice. Why call it a Service if Kubernetes already has a resource called Service? You can consider a Knative Service as a Kubernetes Service + Deployment + Ingress on steroids. A Knative Service provides us with a high-level concept to build cloud-native applications without worrying about all the low-level components required in Kubernetes to deploy and access our applications.&lt;/p&gt;

&lt;p&gt;Knative Services, for example, uses an autoscaler which enables our services to be scaled based on demand. Enabling our services to be scaled down to zero when they are not being used – you will notice that, because of this, the serverless term is used quite a lot in the Knative site. Plus it provides an automatic point in time snapshots of our deployed code and configurations, advance traffic routing built on top of a service mesh.&lt;/p&gt;

&lt;p&gt;With Knative Eventing we can define Event producers and Event consumers in a decoupled way – enabling our applications to be built independently. Knative Eventing allows us to push the decision on how our applications will communicate with each other (transports) to later stages.&lt;/p&gt;

&lt;p&gt;If you are a Java Developer like me, implementing services or microservices is something that we do by writing Spring Boot applications, these applications are going to be our Knative Services. If we are building highly scalable systems, it is quite common to rely on a messaging infrastructure to communicate our services. Messaging tools such as Kafka, RabbitMQ and others provide our services guarantees about message delivery and an out of the box retry mechanism for when things go wrong. On top of Spring Boot, we have frameworks such as &lt;a href="https://salaboy.com/2017/07/26/streams-and-rest-endpoints/"&gt;Spring Cloud Streams&lt;/a&gt; that came to make our life easier by abstracting all the low-level details that we need to know while using these messaging tools (Kafka, RabbitMQ, Google PubSub, etc). This push us to understand how frameworks such as Spring Cloud Streams will work with Knative Eventing, so let’s get our hands dirty with some examples that you can run in your cluster.&lt;/p&gt;

&lt;h1&gt;
  
  
  Did I hear “Hello World”?
&lt;/h1&gt;

&lt;p&gt;Now we have Knative installed with Gloo, let’s give it a try by creating a simple example. As usual, for any Kubernetes deployment we will need to create our app, then a Docker Image and then some YAML files to deploy our application into a cluster. We will be pushing these Docker Images to &lt;a href="http://hub.docker.com"&gt;http://hub.docker.com&lt;/a&gt; so you will need to have an account there.&lt;/p&gt;

&lt;p&gt;Repository here: &lt;a href="https://github.com/salaboy/knative-hello-world.git"&gt;https://github.com/salaboy/knative-hello-world&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The simple SpringBoot Application in Java, which exposes a REST Endpoint&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/salaboy/knative-hello-world/blob/master/src/main/java/com/salaboy/knative/knativehelloworld/KnativeHelloWorldApplication.java#L29"&gt;&lt;code&gt;KnativeHelloWorldApplication.java&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootApplication
@RestController
public class KnativeHelloWorldApplication {
... 
  @GetMapping("/{name}") 
  public String hello(@PathVariable("name") String name) { 
    return "Hello there Knative Traveller: " + name; 
  }
...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We need to compile this project with&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;mvn clean package&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To generate the fat-jar into the &lt;code&gt;target/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;The most basic &lt;strong&gt;Dockerfile&lt;/strong&gt; using OpenJDK:11 slim&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM openjdk:11-jre-slim
COPY target/\*.jar /app.jar
CMD ["java", "-jar", "app.jar"]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We need to build the docker image with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;docker build -t /knative-hello-world .&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then push to docker hub with&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;docker push /knative-hello-world&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And here is where Knative starts helping us to focus on our business logic instead of writing tons of YAML files for Kubernetes. For Knative we just need a single Knative Service manifest:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kservice.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: serving.knative.dev/v1
kind: Service
metadata: 
  name: knative-hello-world
spec: 
  template: 
    spec: 
      containers: 
      - image: salaboy/knative-hello-world
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;kubectl apply -f kservice.yaml&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When a Knative Service is created, Knative automatically creates other resources (Configuration, Route, and Revision) including a Kubernetes Service, a Deployment and an Ingress. On the Knative side the following resources are automatically created:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;service.serving.knative.dev&lt;/li&gt;
&lt;li&gt;route.serving.knative.dev&lt;/li&gt;
&lt;li&gt;configuration.serving.knative.dev&lt;/li&gt;
&lt;li&gt;revision.serving.knative.dev&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--juCggb1A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--juCggb1A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This Knative Service will be automatically downscaled to 0 if there is no traffic going hitting the service after 90 seconds of inactivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interacting with our new Knative Service
&lt;/h2&gt;

&lt;p&gt;Once we have our Knative Service up and running we can get more information by using &lt;code&gt;kubectl&lt;/code&gt; :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl get ksvc&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will see that the Knative Service exposes the URL that we can use to contact our Knative Service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SubJEf5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SubJEf5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-1.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;http://knative-hello-world.default.example.com&lt;/code&gt; is definitely not reachable as we probably don’t own the domain &lt;code&gt;example.com&lt;/code&gt;. In order to find the external IP from our ingress controller we can run:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl get svc -A&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This should list the &lt;code&gt;knative-external-proxy&lt;/code&gt; which is a LoadBalancer and has an External IP&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;gloo-system knative-external-proxy LoadBalancer  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then with this address, we can curl our service by setting the Host header to the request, so it gets redirected inside the cluster to our Knative Service.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;curl -H “Host: knative-hello-world.default.example.com” &lt;a href="http://&amp;lt;EXTERNAL"&gt;http://&amp;lt;EXTERNAL&lt;/a&gt; IP&amp;gt;/salaboy -v&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice: that we need to include the Host header just because we don’t have a publicly available domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Curl -H what? Why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are running on a Cloud Provider which can provision a LoadBalancer with a Public Ip, something that we can do is use XIP.io and configure Gloo DNS to use a XIP.io address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://knative.dev/docs/install/knative-with-gloo/"&gt;https://knative.dev/docs/install/knative-with-gloo/&lt;/a&gt; -&amp;gt; Configuring DNS&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl edit cm config-domain –namespace knative-serving&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And modify it to look like &lt;a href="https://github.com/salaboy/knative-getting-started-java-resources/blob/master/gloo/configmap-dns.yaml"&gt;this&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata: 
  name: config-domain 
  namespace: knative-serving
data: 
# xip.io is a "magic" DNS provider, which resolves all DNS lookups for: 
# \*.{ip}.xip.io to {ip}. 
  &amp;lt;EXTERNAL\_IP&amp;gt;.xip.io: ""
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can use XIP.io to have a subdomain which is linked to your transforming the previous curl to&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;curl &lt;a href="http://knative-hello-world.default.&amp;lt;EXTERNAL"&gt;http://knative-hello-world.default.&amp;lt;EXTERNAL&lt;/a&gt; IP&amp;gt;.xip.io/salaboy -v&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is much nicer. With just a Knative Service deployment we have a public route that we can expose for people to consume outside the cluster. Notice, no Ingress + Service + Deployment configurations required besides our Knative Service. Knative Serving will take care of managing the lifecycle of all the Kubernetes Core resources required for our application to run.&lt;/p&gt;

&lt;h1&gt;
  
  
  “Hello World”s are for kids, bring it on!
&lt;/h1&gt;

&lt;p&gt;If we are designing a distributed system we might want to communicate between different services. &lt;a href="//cloudevents.io"&gt;Cloud Events&lt;/a&gt; are becoming a popular way to do that by interchanging data in a common format/envelope. Luckily for us, Knative Eventing already supports Cloud Events and we can use that straight away. Knative Eventing gives us a set of components that enable late-binding for event sources (producers) and event consumers. This means that we can create our consumers and producers in a generic way and then link them together at runtime.&lt;/p&gt;

&lt;p&gt;Let’s start simple, let’s modify our simple Knative Service from before to accept Cloud Events. Cloud Events and how we receive them will vary depending on which transport we want to use, but the content will always be the same. Because we want to start simple, we will expose an HTTP endpoint to accept CloudEvents.&lt;/p&gt;

&lt;p&gt;Repository here: &lt;a href="https://github.com/salaboy/knative-hello-world.git"&gt;https://github.com/salaboy/knative-hello-world&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Spring Boot you will do something like &lt;a href="https://github.com/salaboy/knative-hello-world/blob/master/src/main/java/com/salaboy/knative/knativehelloworld/KnativeHelloWorldApplication.java#L37"&gt;this&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
@PostMapping
public String recieveCloudEvent(@RequestHeader Map&amp;lt;String, String&amp;gt; headers, @RequestBody Object body) { 
  CloudEvent&amp;lt;AttributesImpl, String&amp;gt; cloudEvent = CloudEventsHelper.parseFromRequest(headers, body); 
...
}
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can send a CloudEvent with curl by adding the right headers&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;curl POST &lt;a href="http://knative-hello-world.default.&amp;lt;EXTERNAL"&gt;http://knative-hello-world.default.&amp;lt;EXTERNAL&lt;/a&gt; IP&amp;gt;.xip.io -H “Content-Type: application/json” -H “ce-id: 536808d3” -H “ce-type: my-first-cloud-event” -H “ce-source: curl” -d ‘{“name”:”salaboy”}’ -v&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice: &lt;code&gt;ce-type: my-first-cloud-event&lt;/code&gt; which represents what kind of event it is. We can use this to decide if we are interested in it or not. Both the data (send with &lt;code&gt;-d&lt;/code&gt;) and the &lt;code&gt;ce-type&lt;/code&gt; are user-defined. Cloud Events doesn’t impose any restrictions on the data that is sent.&lt;/p&gt;

&lt;p&gt;Notice: &lt;code&gt;Content-Type: application/json&lt;/code&gt;, to avoid sending a form-data content.&lt;/p&gt;

&lt;p&gt;And there you go, now every other application producing CloudEvents can send events to our small application.&lt;/p&gt;

&lt;p&gt;When you look at Knative you will find that there are a lot of available Event Sources already, for example, &lt;code&gt;KubernetesEventSource&lt;/code&gt;, &lt;code&gt;GitHubSource&lt;/code&gt;, &lt;code&gt;GcpPubSubSource&lt;/code&gt;, &lt;code&gt;AwsSqsSource&lt;/code&gt;, &lt;code&gt;ContainerSource&lt;/code&gt;, &lt;code&gt;CronJobSource&lt;/code&gt;, &lt;code&gt;KafkaSource&lt;/code&gt;, &lt;code&gt;CamelSource&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But let’s create our own producer, another spring boot application that just sends a CloudEvent by posting content via HTTP.&lt;/p&gt;

&lt;p&gt;Repository here: &lt;a href="https://github.com/salaboy/knative-event-producer.git"&gt;https://github.com/salaboy/knative-event-producer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;KnativeEventProducerApplication.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootApplication
@RestController
public class KnativeEventProducerApplication {

  ...

    @Value("${SINK_HOST:localhost}")
    private String HOST;


    @GetMapping("/{name}")
    public String doSomethingAndSendCloudEvent(@PathVariable("name") String name) {

        final CloudEvent&amp;lt;AttributesImpl, String&amp;gt; myCloudEvent = CloudEventBuilder.&amp;lt;String&amp;gt;builder()
                .withId("ABC-123")
                .withType("my-first-cloud-event")
                .withSource(URI.create("knative-event-producer.default.svc.cluster.local"))
                .withData("{\"name\" : \"" + name + "-" + UUID.randomUUID().toString() + "\" }")
                .withDatacontenttype("application/json")
                .build();

        WebClient webClient = WebClient.builder().baseUrl(HOST).filter(logRequest()).build();

        WebClient.ResponseSpec postCloudEvent = CloudEventsHelper.createPostCloudEvent(webClient, myCloudEvent);

        postCloudEvent.bodyToMono(String.class).doOnError(t -&amp;gt; t.printStackTrace())
                .doOnSuccess(s -&amp;gt; System.out.println("Result -&amp;gt; " + s)).subscribe();

        return "OK!";

    }
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;kservice.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: knative-event-producer
spec:
  template:
    spec:
      containers:
        - image: salaboy/knative-event-producer
          env:
            - name: SINK_HOST
              value: knative-hello-world.default.&amp;lt;EXTERNAL IP&amp;gt;.xip.io
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice: now we are configuring the &lt;code&gt;SINK&lt;/code&gt; for the events produced in our service with an Environment Variable called &lt;code&gt;SINK_HOST&lt;/code&gt; and we are pointing to the internal DNS name for our &lt;code&gt;knative-hello-world&lt;/code&gt; Service.&lt;/p&gt;

&lt;p&gt;If you build the project, the Docker image and then apply this Knative Service manifest, you can curl the event producer to emit a CloudEvent to our Knative Hello World Service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AzeJW-dA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AzeJW-dA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have two services exchanging data using CloudEvents, that is pretty cool, but let’s take it up a notch.&lt;/p&gt;

&lt;h1&gt;
  
  
  Toys for Grownups (aka Kafka)
&lt;/h1&gt;

&lt;p&gt;In a real distributed application, you might want to use all the power of messaging and streaming of information. For such scenarios, Kafka is becoming a very popular option, so let’s give it a try with Knative.&lt;/p&gt;

&lt;p&gt;In this scenario, we will have an application producing Kafka messages and we want to route the content of these messages to our HTTP CloudEvent consumer endpoint. We haven’t designed any of these applications to talk to each other, but because we are using CloudEvents (and JSON payloads) they can now interchange information.&lt;/p&gt;

&lt;p&gt;In order to get this working we need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Kafka or have it running somewhere where it is reachable by the cluster&lt;/li&gt;
&lt;li&gt;Install KafkaSource for Knative&lt;/li&gt;
&lt;li&gt;Create a Kafka Source for Knative to understand where the messages are coming from and where are they going. This is referred to as ‘late binding’ because you change the source, create new ones or remove them in runtime.&lt;/li&gt;
&lt;li&gt;Produce Kafka messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s install Kafka in our cluster using Helm:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;helm repo add incubator &lt;a href="http://storage.googleapis.com/kubernetes-charts-incubator"&gt;http://storage.googleapis.com/kubernetes-charts-incubator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;helm install my-kafka incubator/kafka&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next we need to install KafkaSource for Knative&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl apply -f &lt;a href="https://storage.googleapis.com/knative-releases/eventing-contrib/latest/kafka-source.yaml"&gt;https://storage.googleapis.com/knative-releases/eventing-contrib/latest/kafka-source.yaml&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we are ready to create our Kafka Source with a sink pointing to our &lt;code&gt;knative-hello-world&lt;/code&gt; Knative Service:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kafka-knative-source.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: sources.eventing.knative.dev/v1alpha1
kind: KafkaSource
metadata:
  name: kafka-source
spec:
  consumerGroup: knative-group
  bootstrapServers: my-kafka:9092 #note the kafka namespace
  topics: knative-topic
  sink:
    ref:
      apiVersion: serving.knative.dev/v1
      kind: Service
      name: knative-hello-world
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can send messages to the &lt;code&gt;knative-topic&lt;/code&gt; and they will be automatically forward to our Knative Service called &lt;code&gt;knative-hello-world&lt;/code&gt;. Notice that &lt;code&gt;my-kafka&lt;/code&gt; is the name of the Kubernetes service that was created by installing Kafka with Helm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cbdPZn4L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cbdPZn4L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-3.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A very lazy way to post messages to the &lt;code&gt;knative-topic&lt;/code&gt; might be using a Kafka client from a Docker container, like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl run kafka-producer -ti –image=strimzi/kafka:0.14.0-kafka-2.3.0 –rm=true –restart=Never — bin/kafka-console-producer.sh –broker-list my-kafka:9092 –topic knative-topic&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then type a message in the prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;{“msg”: “This is a test!”}&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;p&gt;That will send a Kafka message, which will be transformed into a cloud event and forwarded to our HTTP Cloud Event consumer (&lt;code&gt;knative-hello-world&lt;/code&gt; Knative Service).&lt;/p&gt;

&lt;h1&gt;
  
  
  How would you do it for real?
&lt;/h1&gt;

&lt;p&gt;In a real project, it really doesn’t matter how you produce the Kafka message. One option would be to just grab the Kafka Java APIs and make your application write messages to the previous Kafka topic. But if you really like the late-binding approach you can leverage that from your Spring Boot applications as well by using Spring Cloud Streams, which gives you a common API for different messaging providers.&lt;/p&gt;

&lt;p&gt;If we want to now create a Spring Boot application that can send messages to the Kafka Topic that we previously defined, we just need to use Spring Cloud Streams dependencies and the Kafka Binder. You can find the source code of this example here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/salaboy/knative-spring-cloud-event-producer"&gt;https://github.com/salaboy/knative-spring-cloud-event-producer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pom.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependencies&amp;gt;
  &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-cloud-stream&amp;lt;/artifactId&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-cloud-stream-binder-kafka&amp;lt;/artifactId&amp;gt;
  &amp;lt;/dependency&amp;gt;
...
&amp;lt;/dependencies&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then a simple application that sends messages&lt;/p&gt;

&lt;p&gt;&lt;code&gt;KafkaProducerApplication.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootApplication
@EnableBinding(MyChannels.class)
@EnableScheduling
public class KafkaProducerApplication {

  @Autowired
  private MessageChannel myProducer;

  ...

  @Scheduled(fixedDelay = 3000)
  public void sendMessageEveryX() {
    System.out.println("&amp;gt; Sending a message...");
    myProducer.send(MessageBuilder.withPayload("{\"name\":\"salaboy : " + UUID.randomUUID().toString() + " \"}").build());
  }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This simple app will send a message every 3 seconds, but where?&lt;/p&gt;

&lt;p&gt;That is late binding in action. Where and which &lt;code&gt;binder&lt;/code&gt; (which messaging implementation) can be defined later on. In this case, we can do that by changing the applications.properties file with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;application.properties&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring.cloud.stream.kafka.binder.brokers=my-kafka
spring.cloud.stream.kafka.binder.defaultBrokerPort=9092
spring.cloud.stream.bindings.myProducer.destination=knative-topic
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But because we are working with Docker, we can easily do that with Environment Variables as well. Meaning that our container will not have these details hard coded and we will be able to reuse the same docker image in different environments with different Kafka installations and different topics.&lt;/p&gt;

&lt;p&gt;To build the project you can run:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;mvn clean package&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will need to build this docker image with:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;docker build -t /knative-spring-cloud-event-producer .&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then you can define your Knative Service:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;knative.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: knative-spring-cloud-event-producer
spec:
  template:
    metadata:
      annotations:
        autoscaling.knative.dev/minScale: "1"
    spec:
      containers:
        - image: salaboy/knative-spring-cloud-event-producer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D1u29rXO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D1u29rXO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2020/02/null-4.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice: that our application doesn’t expect any HTTP request. By default, Knative autoscaler will downscale the application based on traffic. For this particular scenario, we don’t want our application to get downscaled, for that reason we use the annotation: &lt;code&gt;autoscaling.knative.dev/minScale: "1"&lt;/code&gt;. This will keep at least one instance of our service running at all times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can create this Knative service by applying this file into your cluster:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl apply -f kservice.yaml&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you log the output of the knative-hello-world pod you will see that every 3 seconds you will receive a Cloud Event.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;kubectl logs -f knative-hello-world-&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can try removing the &lt;code&gt;autoscaling.knative.dev/minScale: "1"&lt;/code&gt; and see how after 90 seconds your pod is scaled down to zero, as there is no traffic going to your event producer.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sum Up
&lt;/h1&gt;

&lt;p&gt;There you have it, an example that uses Knative Serving + Knative Eventing + HTTP Transport Cloud Events + Knative Kafka Source + Spring Cloud Streams.&lt;/p&gt;

&lt;p&gt;This is quite a mouthful, but this blog post covered all the pieces that you will need to build highly distributed applications that can scale using Knative and Kafka. As we have seen in this blog post, Knative provides a programming model on top of Kubernetes concepts which allows us to concentrate on our applications instead of how Kubernetes will deploy our application, or how it will route requests to it. Knative will automatically downscale to zero our service if it is not being used, something that cannot be achieved with plain Kubernetes. We have also experimented with Cloud Events and Knative Eventing, to demonstrate a powerful and robust approach to communicate between our services while using messaging and late binding.&lt;/p&gt;

&lt;p&gt;In future blog posts, I will be sharing some details about how Knative and Zeebe ( &lt;a href="http://zeebe.io"&gt;http://zeebe.io&lt;/a&gt; ) integration is being built to provide features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long-lived and highly scalable orchestration Service and functions orchestration leveraging late binding&lt;/li&gt;
&lt;li&gt;Cloud Events orchestration, sequencing, and monitoring&lt;/li&gt;
&lt;li&gt;A framework for application development built on top of Knative which provides business visibility and business insights to non-technical people&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have comments, suggestions or questions feel free to reach out as I will be evolving the examples.&lt;/p&gt;

</description>
      <category>knative</category>
      <category>cloudnative</category>
      <category>tutorial</category>
      <category>java</category>
    </item>
    <item>
      <title>2019/2020</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Fri, 03 Jan 2020 10:11:59 +0000</pubDate>
      <link>https://dev.to/salaboy/2019-2020-4lj3</link>
      <guid>https://dev.to/salaboy/2019-2020-4lj3</guid>
      <description>&lt;p&gt;I’ve learned a lot of valuable lessons in 2019, this blog post it is just a quick summary of the year and my experiences while working with Open Source technologies such as &lt;a href="http://kubernetes.io"&gt;Kubernetes&lt;/a&gt;, &lt;a href="http://zeebe.io"&gt;Zeebe&lt;/a&gt;, &lt;a href="http://jenkins-x.io"&gt;Jenkins X&lt;/a&gt;, &lt;a href="https://spring.io/projects/spring-cloud"&gt;Spring Cloud&lt;/a&gt;, &lt;a href="http://camunda.com"&gt;Camunda BPM&lt;/a&gt;, &lt;a href="http://jhipster.tech"&gt;JHipster&lt;/a&gt;, &lt;a href="https://github.com/kubernetes-sigs/kubebuilder"&gt;KubeBuilder&lt;/a&gt;, etc. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Stay Focused / Reduce Stress&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;During 2019, I’ve faced a lot of challenges around finding the right activities to focus on. Being on the road presenting, being involved in several projects which require active development, preparing new proposals, and engaging with different communities lead me to not being able to make progress or even finding which were the key initiatives that really deserved my attention. &lt;/p&gt;

&lt;p&gt;Lucky, in the second half of 2019, I was fortunate enough to meet new friends that helped me to stay focused and reduce stress levels. In general, this was achieved by choosing the right things to do, the right conferences to present at and the right way to scope and measure progress around my work.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Company Culture is a must&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It can make such a difference when you are in a company that has the right culture, you immediately notice the change. &lt;a href="http://camunda.com"&gt;Camunda&lt;/a&gt; has over-delivered in this angle. I’ve definitely learned a big lesson in 2019, technology matters but without the right culture, it is impossible to sustain or even find the right path and speed to achieve great things. As has been said before, culture is ever-shifting and based on people, so it feels to me that I am up to keep learning on how the company cultivates and improve its culture as it grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Keep Learning + Keep Sharing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In 2019, I’ve decided that I wanted to be out of my comfort zone and I set up some projects to learn new things. After being in the Java ecosystem for such a long time, I’ve decided to start with GoLang and this opened the door for a lot of new interactions and also set me up for learning new things in 2020.&lt;/p&gt;

&lt;p&gt;A big part of 2019 was to go out and meet other developers and smart people to understand how they are tackling their Cloud-Native journey, I had the pleasure to present in the following conferences/meetups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MadridJUG, Spain, Dec 19&lt;/li&gt;
&lt;li&gt;CoimbraJUG, Portugal, Dec 19&lt;/li&gt;
&lt;li&gt;Jenkins World Lisbon, Portugal, Dec 19&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/salaboy/from-monolith-to-kubernetes-webinar-with-cloudbees-5dk8-temp-slug-49730"&gt;Jenkins X Webinar 19&lt;/a&gt; (Online), Nov 19&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/salaboy/boosting-your-kubectl-productivity-kubecon-4cne-temp-slug-1985387"&gt;KubeCon US San Diego 19 / CD Foundation Summit&lt;/a&gt;, USA, Nov 19&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/salaboy/from-monolith-to-k8s-soujava-3g1j-temp-slug-3970700"&gt;SouJava Webinar 19&lt;/a&gt; (Online), Nov 19&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/salaboy/jenkins-x-spring-cloud-zeebe-geecon-prague-2019-39db-temp-slug-8835586"&gt;GeeCon Prague 19&lt;/a&gt;, Prague, Czech Republic, Oct 19&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.slideshare.net/salaboy/how-open-source-is-funded-ljc-london-sept-2019"&gt;London Java Community Meetup 19&lt;/a&gt;, London, UK, Sept 19&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salaboy.com/2019/08/15/jenkinsworld-2019-san-fransisco-usa/"&gt;Jenkins World San Francisco, USA, Aug 19&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salaboy.com/2019/07/03/jhipster-conf-rocks/"&gt;JHipster Conf Paris, France – June 19&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salaboy.com/2019/05/28/creating-k8s-operators-with-spring-cloud/"&gt;JBCNConf, Barcelona, Spain – May 19&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salaboy.com/2019/03/20/community-meetups-march-19/"&gt;La Plata University Meetup, Mar del Plata, Argentina – March 19&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salaboy.com/2019/03/20/community-meetups-march-19/"&gt;Healthcare in Gov Meetup, Buenos Aires, Argentina – March 19&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salaboy.com/2019/03/20/community-meetups-march-19/"&gt;London DevOps Meetup, London, UK – March 19&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://salaboy.com/2019/02/01/activiti-cloud-devcon-2019/"&gt;Alfresco DevCon, Dublin, Ireland, Jan 19&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where my last presentation of the year focused on the path from a Java Monolith to Kubernetes focusing on two tools that can make your life easier: &lt;a href="http://jenkins-x.io"&gt;Jenkins X&lt;/a&gt; for CI/CD on Kubernetes and &lt;a href="https://docs.zeebe.io/kubernetes/index.html"&gt;Zeebe&lt;/a&gt; for MicroServices and Functions Orchestration in Kubernetes.&lt;/p&gt;

&lt;p&gt;I am still blown away by speaking at &lt;a href="https://dev.to/salaboy/boosting-your-kubectl-productivity-kubecon-4cne-temp-slug-1985387"&gt;KubeCon US in front of 4000+ people&lt;/a&gt;. So it is worth mentioning that I had a lot of fun Learning and Sharing being part of &lt;a href="http://learnk8s.io"&gt;LearnK8s.io&lt;/a&gt;, in 2020 I expect this relationship to grow and I hope to be able to meet all the &lt;a href="https://learnk8s.io/about-us"&gt;LearnK8s&lt;/a&gt; team face to face.   &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What’s next&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There are several things coming my way on 2020, Kubernetes and Orchestration is still my main focus, but I want to focus on getting heavily involved with new communities where I am still a newbie. You can expect the &lt;a href="https://dev.to/salaboy/zeebe-kubernetes-operator-1g59-temp-slug-3049877"&gt;Zeebe Kubernetes Operator&lt;/a&gt; to evolve iteratively along with the &lt;a href="http://helm.zeebe.io"&gt;Zeebe Helm Charts&lt;/a&gt; as there is a lot of work to do on those fronts. I am really interested in making the life of Developers using these tools as simple as possible, so if you are looking into these tools get in touch and we can work together on some cool projects. &lt;/p&gt;

&lt;p&gt;I will not spoil too much now but stay tuned for more news. I will try to keep my twitter updated with 2020 conferences, so I am looking forward to meeting you all.&lt;/p&gt;

</description>
      <category>bpm</category>
      <category>bpmn2</category>
      <category>camunda</category>
      <category>cicd</category>
    </item>
    <item>
      <title>Zeebe Kubernetes Operator</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Fri, 20 Dec 2019 09:34:24 +0000</pubDate>
      <link>https://dev.to/salaboy/zeebe-kubernetes-operator-4k0e</link>
      <guid>https://dev.to/salaboy/zeebe-kubernetes-operator-4k0e</guid>
      <description>&lt;p&gt;The &lt;strong&gt;&lt;em&gt;Zeebe Kubernetes Operator&lt;/em&gt;&lt;/strong&gt; was born out of the need to manage more than one single Zeebe Cluster running inside Kubernetes Clusters. Zeebe Clusters have their own lifecycle and in real implementations, the need to update, monitor and manage some of these cluster components while applications are running becomes challenging. The objective of the Zeebe k8s Operator is to simplify and natively integrate Zeebe with k8s, to solve operational burden and facilitate the creation and maintenance of a set of clusters. &lt;/p&gt;

&lt;p&gt;This operator has been built with &lt;a href="https://github.com/helm/helm"&gt;Kubernetes Helm&lt;/a&gt; in mind, meaning that at the end of the day, this operator will be in charge of managing &lt;a href="https://helm.sh/docs/topics/charts/"&gt;Helm Charts&lt;/a&gt;. If you are not familiar with Helm, Helm is a package manager for Kubernetes, which help us to package and distribute Kubernetes manifest. Helm also deals with installing, labeling and dependency management between packages (charts). Because we have Zeebe Helm packages already here: &lt;a href="http://helm.zeebe.io"&gt;http://helm.zeebe.io&lt;/a&gt; which are automatically versioned and released, the &lt;strong&gt;&lt;em&gt;Zeebe Kubernetes Operator&lt;/em&gt;&lt;/strong&gt; will use these charts to create and manage new clusters and other related components. &lt;/p&gt;

&lt;p&gt;Because we are in Kubernetes realms we need to provide a declarative way of stating that we want a new Zeebe Cluster to be provisioned. For this reason, the &lt;a href="https://github.com/salaboy/zeebe-operator/blob/master/charts/zeebe-operator/templates/zeebe.io_zeebeclusters.yaml#L18"&gt;&lt;strong&gt;&lt;em&gt;ZeebeCluster&lt;/em&gt;&lt;/strong&gt; Custom Resource Definition ( &lt;strong&gt;CRD&lt;/strong&gt; )&lt;/a&gt;is introduced. This resource contains all the information needed to provision a cluster and it will also reflect the current cluster status. The Zeebe Kubernetes Operator is built to monitor &lt;strong&gt;&lt;em&gt;ZeebeCluster&lt;/em&gt;&lt;/strong&gt; resources and interact with the Kubernetes APIs under the hood to make sure that the Zeebe Cluster is provisioned, upgraded or deleted correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;The Zeebe Kubernetes Operator can be installed using Helm, as it is provided as a Helm Chart as well. In contrast with &lt;a href="https://github.com/zeebe-io/zeebe-cluster-helm"&gt;zeebe-cluster&lt;/a&gt; , &lt;a href="https://github.com/zeebe-io/zeebe-operate-helm"&gt;zeebe-operate&lt;/a&gt; and &lt;a href="https://github.com/zeebe-io/zeebe-full-helm"&gt;zeebe-full&lt;/a&gt; charts, the operator chart installation by itself doesn’t install any Zeebe Cluster, but allows you to do that by creating ZeebeCluster CRD resources. &lt;/p&gt;

&lt;p&gt;The following steps will guide you to install the Operator with &lt;a href="https://helm.sh/docs/intro/install/"&gt;Helm3&lt;/a&gt;  (which is the default version now)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This will also work if you have correctly installed Helm2 in your cluster with tiller.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add the Zeebe Helm Repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm repo add zeebe https://helm.zeebe.io helm repo update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now you are ready to install the Zeebe Kubernetes Operator:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;helm install zeebe-operator zeebe/zeebe-operator&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Create &lt;strong&gt;&lt;em&gt;my-zeebe-cluster.yaml&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: zeebe.zeebe.io/v1 kind: ZeebeCluster metadata:   name: my-zeebe-cluster
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Create the resource with in the Kubernetes cluster with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f my-zeebe-cluster.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will create a new namespace with the name stated in the ZeebeCluster resource ( &lt;code&gt;ZeebeCluster.metadata.name&lt;/code&gt; ) and provision a new Zeebe Cluster plus ElasticSearch by default.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Future versions will allow you to specify in the ZeebeCluster resource which ElasticSearch instance to use. &lt;/p&gt;

&lt;p&gt;Notice that the first time provisioning a cluster, docker images will need to be downloaded to the Kubernetes Docker Registry so the first cluster might take more time to be provisioned. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can now query for your Zeebe Clusters using the &lt;code&gt;kubectl&lt;/code&gt; CLI:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get zb&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you delete the &lt;strong&gt;&lt;em&gt;ZeebeCluster&lt;/em&gt;&lt;/strong&gt; resource the actual &lt;strong&gt;&lt;em&gt;ZeebeCluster&lt;/em&gt;&lt;/strong&gt; will be automatically removed from your cluster. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now you can check that there is a new “ &lt;strong&gt;&lt;em&gt;Namespace&lt;/em&gt;&lt;/strong&gt; ” created with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get ns&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And also check that the cluster is correctly provisioned by looking at the Pods created inside the newly created namespace with&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get pods -n &amp;lt;Zeebe Cluster Name&amp;gt; -w&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The next video show these commands in action along with the installation of the &lt;strong&gt;&lt;em&gt;Zeebe Kubernetes Operator:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Details and Dependencies
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;This Kubernetes Operator was built using KubeBuilder V2.1+, Tekton 0.8.0+ and Helm 3.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Operator Defines currently 1 CRD: ZeebeCluster, but in future versions, new types will be defined for other components such as Zeebe Operate and Workers.  The &lt;strong&gt;&lt;em&gt;ZeebeCluster&lt;/em&gt;&lt;/strong&gt; resource represent a low-level resource which will instantiate a Zeebe Cluster based on predefined parameters. This low-level resource definition can be used to define the cluster topology and HA configurations.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;em&gt;Zeebe Kubernetes Operator&lt;/em&gt;&lt;/strong&gt; was built using the &lt;a href="https://github.com/kubernetes-sigs/kubebuilder"&gt;kubebuilder framework&lt;/a&gt; for writing the controller’s logic and scaffolding the CRD type. Internally it does interact with &lt;a href="https://github.com/tektoncd/pipeline"&gt;Tekton Pipelines&lt;/a&gt; in order to install and manage Zeebe Helm Charts.  The project itself is being built, released and tested using &lt;a href="https://jenkins-x.io"&gt;Jenkins X&lt;/a&gt;. This lead to some changes in how KubeBuilder’s project is structured, as in it current shape the project is not organised in a way that is easy to create a Helm Chart out of it.&lt;/p&gt;

&lt;p&gt;The main flow of the Operator works like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qCpW-wOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/1zDKuTI6MwYKixRere84WtGFSImYddBjuktyARCti4GGX_PN29OHh8nJdA3oCLlz2gxkvnLA96mvUmz45wfUelnv80hoZdCK4FH7QbsqTnOcmf9-Bdaz3GMV8JzhuTKlbTobjj71" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qCpW-wOY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/1zDKuTI6MwYKixRere84WtGFSImYddBjuktyARCti4GGX_PN29OHh8nJdA3oCLlz2gxkvnLA96mvUmz45wfUelnv80hoZdCK4FH7QbsqTnOcmf9-Bdaz3GMV8JzhuTKlbTobjj71" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, the Operator will be constantly looking for &lt;strong&gt;&lt;em&gt;ZeebeCluster&lt;/em&gt;&lt;/strong&gt; resources, when one is found a new &lt;strong&gt;Namespace&lt;/strong&gt; is created and a &lt;a href="https://github.com/tektoncd/pipeline/tree/v0.8.0/docs#tekton-pipelines"&gt;Tekton Task and TaskRun&lt;/a&gt; are created to “upgrade” the Helm Charts defined inside the Version Stream repository (for now hosted here: &lt;a href="https://github.com/salaboy/zeebe-base-chart"&gt;https://github.com/salaboy/zeebe-base-chart&lt;/a&gt; ).&lt;/p&gt;

&lt;p&gt;This repository (referred as &lt;strong&gt;&lt;em&gt;Version Stream Repository&lt;/em&gt;&lt;/strong&gt; ) contains a list of blessed versions that will be installed when a new &lt;strong&gt;ZeebeCluster&lt;/strong&gt; resource is detected by the operator. Using a Version Stream Repository provide us with the flexibility to evolve the operator code and the charts that define what needs to be provisioned independently. Allowing a simple upgrade path to future versions by using a Git repository as central reference to a stable version.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In future versions, the option to choose a version stream repository will be provided. Allowing different streams&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Task created in Tekton Pipelines execute two basic operations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone Version Stream Repository (using simple &lt;code&gt;git clone&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Run Helm Upgrade of the chart defined in the Version Stream Repository (it does actually an upgrade/install if it doesn’t exist)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second step, running Helm upgrade/install will create a Helm Release which can be upgraded if new versions of the charts are available. These releases can be queried using the Helm cli tool: &lt;code&gt;helm list --all-namespaces&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once the Task is created an execution is triggered by the creation of a TaskRun (an actual instance of the task) and the operator will monitor for this task to be completed. Once the task is completed, the Operator watch for the &lt;strong&gt;Zeebe Cluster&lt;/strong&gt; to be provisioned. In a more detail look, the Operator will look for a StatefulSet (Zeebe Broker Nodes) with a set of labels matching the &lt;strong&gt;ZeebeCluster&lt;/strong&gt; name, inside the created namespace.&lt;/p&gt;

&lt;p&gt;Once the &lt;strong&gt;&lt;em&gt;StatefulSet&lt;/em&gt;&lt;/strong&gt; is located, the Operator assign the &lt;strong&gt;&lt;em&gt;ZeebeCluster&lt;/em&gt;&lt;/strong&gt; resource as the _ &lt;strong&gt;Owner&lt;/strong&gt; _ of this &lt;strong&gt;&lt;em&gt;StatefulSet&lt;/em&gt;&lt;/strong&gt; , hence it will be notified about the changes emitted by the resources associated to the &lt;strong&gt;&lt;em&gt;StatefulSet&lt;/em&gt;&lt;/strong&gt;. This allows the Operator to externalise a Health Status of the Zeebe Cluster at any given point, understanding the actual state of the cluster itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sum up
&lt;/h2&gt;

&lt;p&gt;The Zeebe Kubernetes Operator helps you to create and manage Zeebe Clusters. It uses Tekton Pipelines and Helm3 to actually provision these clusters. Each ZeebeCluster will correspond with a different Kubernetes Namespace, which provide resources and data isolation, as currently an ElasticSearch Cluster is provisioned as part of the Zeebe Cluster Helm Chart.&lt;/p&gt;

&lt;p&gt;Future versions will include more advanced management features and other components related to the ZeebeCluster, such as Zeebe Operate, infrastructure tools such as Prometheus. If you want to contribute with the project and get involved early on into making this operator awesome, drop me a message as I have at least 20 issues pending in my TODO list.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The source code of the operator will probably find a new home in the Zeebe organisation early next year.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>kubernetes</category>
      <category>zeebe</category>
      <category>cloudnative</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Boosting your `kubectl` productivity @ KubeCon</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Wed, 20 Nov 2019 18:23:16 +0000</pubDate>
      <link>https://dev.to/salaboy/boosting-your-kubectl-productivity-kubecon-49b4</link>
      <guid>https://dev.to/salaboy/boosting-your-kubectl-productivity-kubecon-49b4</guid>
      <description>&lt;p&gt;Oh my.. that was a big stage and a very very large audience, but it was totally worth it! I kinda rushed in the end but I got a lot of positive feedback about the content and a lot of kudos to the &lt;a href="http://twitter.com/learnk8s"&gt;@learnk8s&lt;/a&gt; guys who are doing an amazing job.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1D68L6Sf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-7.jpg%3Fw%3D510" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1D68L6Sf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-7.jpg%3Fw%3D510" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Jow64WeA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-5.jpg%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Jow64WeA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-5.jpg%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B9piBW5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-4.jpg%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B9piBW5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-4.jpg%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rffncvuM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-3.jpg%3Fw%3D680" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rffncvuM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-3.jpg%3Fw%3D680" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6kW0fzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-2.jpg%3Fw%3D680" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y6kW0fzU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-2.jpg%3Fw%3D680" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tzgsJZlw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-1.jpg%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tzgsJZlw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/salaboy-kubecon-1.jpg%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here some useful links about the projects that I’ve mention during the presentation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://twitter.com/learnk8s"&gt;@LearnK8s&lt;/a&gt; Article: &lt;a href="https://learnk8s.io/blog/kubectl-productivity/"&gt;https://learnk8s.io/blog/kubectl-productivity/&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;KubeCTX and KubeNS: &lt;a href="https://github.com/ahmetb/kubectx"&gt;https://github.com/ahmetb/kubectx&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AutoGen Aliases: &lt;a href="https://github.com/ahmetb/kubectl-aliases"&gt;https://github.com/ahmetb/kubectl-aliases&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Krew: &lt;a href="https://github.com/kubernetes-sigs/krew"&gt;https://github.com/kubernetes-sigs/krew&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;KubeCtl KubeCon Plugin: &lt;a href="https://github.com/salaboy/kubectl-kcon"&gt;https://github.com/salaboy/kubectl-kcon&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also on the &lt;a href="http://cd.foundation"&gt;cd.foundation&lt;/a&gt; summit a quick talk about why &lt;a href="http://jenkins-x.io"&gt;Jenkins X&lt;/a&gt;:&lt;/p&gt;

</description>
      <category>kubecon</category>
      <category>kubernetes</category>
      <category>kubectl</category>
      <category>tips</category>
    </item>
    <item>
      <title>From Monolith to Kubernetes Webinar with CloudBees</title>
      <dc:creator>salaboy</dc:creator>
      <pubDate>Mon, 18 Nov 2019 16:56:45 +0000</pubDate>
      <link>https://dev.to/salaboy/from-monolith-to-kubernetes-webinar-with-cloudbees-3gbn</link>
      <guid>https://dev.to/salaboy/from-monolith-to-kubernetes-webinar-with-cloudbees-3gbn</guid>
      <description>&lt;p&gt;I am super happy to announce that I am doing a Webinar about how to go &lt;strong&gt;&lt;em&gt;“From Monoliths to Kubernetes using Jenkins X”&lt;/em&gt;&lt;/strong&gt;. This is being organised by CloudBees and it is going to happen the &lt;a href="https://register.gotowebinar.com/register/4496029892230348035"&gt;26th Nov 2019&lt;/a&gt;. I will be showing live how to work with multiple projects and what main challenges are you going to face while going cloud native, along the tools (&lt;a href="http://zeebe.io"&gt;Zeebe&lt;/a&gt;, Helm, etc.) that will help you to move faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://register.gotowebinar.com/register/4496029892230348035"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VA9z0vHu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/webinar.jpg%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wO2XY7JJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/from-monolith-to-k8s.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wO2XY7JJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://salaboy.files.wordpress.com/2019/11/from-monolith-to-k8s.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are interested in the webinar please register here: &lt;a href="https://register.gotowebinar.com/register/4496029892230348035"&gt;https://register.gotowebinar.com/register/4496029892230348035&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m really looking forward to hear your questions and comments about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recording
&lt;/h2&gt;

</description>
      <category>kubernetes</category>
      <category>jenkinsx</category>
      <category>microservices</category>
      <category>cloudnative</category>
    </item>
  </channel>
</rss>
