 Perfect. All right. Let's get it done. Right. You go, my friend. Yes. Hello. So, we are very happy to see all of you here on the session. We're going to talk about wiring cloud native applications for local development. And, well, first we need to, of course, assess the audience, how many of you are developers, and it's most of you, which makes us very, very happy because this session is specifically targeting you. We would like to tell you about the tools and approaches that we think are really, really good that can make you writing your cloud native applications a little bit more efficient and happier because, well, unhappy developers don't produce great code and happy developers are very, very efficient. So why, why, what makes developers unhappy? The thing we thought about this, and there is a little bit of a trade-off because production always wins. Whatever the, whatever are the constraints that the production imposes on us, they are very important. Right. Production is where we make money, which is hopefully goes to paying our compensation packages and so on. So it's very, very important. And it's always the most important thing that you will have. And the production will be made easy. And when something is made easy, is because other people are paying for it. Right. So in our situation, is developer pay very often with developer experience to enable the production setups that we want to work with. And this is something that we would like to address today. My name is Alex Shaleff. I work for a developer tools company called AtomicJour. We are the maintainers of the test countries libraries, which is one of the projects we're going to talk later today. My background is mostly in Java. So I'm very happy to see so many Java developers here. And you can find me online and talk to me. I'd love that. Yep. Hello, everyone. My name is Mauricio Salatino. I do work for Diabrit. We help people to run cloud native applications at scale. And I just, I'm super happy this week, super excited because I've just published my book titled Platform Engineering for Kubernetes, on Kubernetes. And this book basically covers a bunch of different tools, mostly from that lab, from a developer perspective of what kind of tools do I need to get stuff up and running. I do cover people like projects from people here in the audience, like Dagger, you know, Knative, and a bunch of other projects like Argo. We have like Argo gone this week as well. So a bunch of projects put together just to enable developers to be a little bit more efficient, as well as some other developer tools. I'm currently working for the Dapper project as a contributor and also as part of the Knative project, as part of the steering committee, and trying to collaborate with the functions working group as well. The reason why I'm here as well is because I do identify as a developer, even if I'm working on more like infra kind of stuff or frameworks around developers in the CNCF. But also my background is closer to Go and closer to Java as well in the past. And yeah, the reason, because we are developers, we are both developers, we thought, okay, let's build a simple pizza application here in Chicago. That's not the typical Chicago pizza. We need to change that for the next one when we go to a different city. But yeah, so we built a simple application because we wanted to demonstrate some of the tools that we are going to be mentioning here, like, you know, with a simple example that people can follow or that they can execute in their own Kubernetes clusters. So I have like, we created this very, very simple pizza store, kind of like a demo. I don't know if you can see it there in the back, but it's pretty simple. Here on the top, basically we have like a fixed order that you can place into the system. And then different services will be processing the order, right? Pretty simple stuff just to demonstrate some concepts. So when I place the order, you can see in the bottom that the order is going to be processed. And on the right hand side, what you can see is like different services, like the store service or the kitchen, you know, service, emitting events and processing the order, doing different things, right? Now the pizza is being cooked. At some point, you know, the pizza is going to be delivered to your address that you specified on the top. And you will get a bunch of events saying, you know, where the pizza is in the delivery process. It's half a mile away. Now the pizza just arrived to the destination. So super, super, super simple application. But even with this level of simplicity, we can just demonstrate how hard it is for developers just to build this kind of things. Yeah, it's a real production application. It's written mostly in Java. And we, when we described, we wanted to not just show the application, but give you the idea of what's the infrastructure behind that. So we described this to a child GPT because nothing is done without child GPT nowadays. And this is what it came up with. Right? So if you're worried about being replaced soon by AI, you still have a little bit of time. Yes, it does, it does, it doesn't, it doesn't generate diagrams very well. So in fact, this is a proper distributed application. It consists of at least three. Actually, it consists of four services that are separate. Well, applications running, we deployed in the Kubernetes cluster. There was a pizza store service there in the middle, which is the sort of the orchestrator and to which the clients are connected. And it works with two others, which is the kitchen and delivery service. They communicate using the Kafka messaging, rocker, and the data is stored in the relational database as like a normal, like a normal application. But it's, it's a small application, right? But it's, it's natural, like with four microservices, if I just replace and rename the boxes, I could build very, very many systems like this, right? It could be my movie recommendation and they like something different or it could be my, my banking solution was for boxes. So it's a very, it's a very real life architecture. And you can play with it in the repository and you can see how it feels and works. So this is the production view of the application, right? This is, we have the Kubernetes there, we have all those things. As a developer, when I'm working on those yellow boxes, right? Because that's, that's the code that I'm working with. What I'm interested in is a different view, only actually the code and maybe the communication between the patterns is what I'm interested in. Everything else is an overhead that I need to, I need to know, I need to master, I need to include into my onboarding for the new people, I need to include that into like the education curricula for new people joining the company if I want them to be effective with this. And that's a lot of great parts that actually are not in the direct interest of me as a developer to work on. This is the toll that I have to pay for, for working in a sort of production like environment and understand that. Yeah, you can, I always use the example of like a student that is joining the company, right? Like, and you need to train them to learn about all these services, even like understanding how the different services interact, it's complicated. Imagine if they need to learn about load balancers or auto scaling. That's too complicated for a developer that's, that's really complicated. The same applies for infrastructure, right? Like if you need to know where the database is or which database, you need to put a student to learn Kafka or deep PostgreSQL features that you're using for your production workloads, workloads that might be too complicated. So usually you face some challenges when you are working with these kind of like applications and distributed applications that runs on top of Kubernetes or on top of a cloud provider, right? Unfamiliar tools for developers, like pushing them to learn, you know, all the AWS services or all the Google cloud services might be quite a lot. Pushing them even like just to learn how Kubernetes works for just deploying their applications might be too much for some people. And sometimes you can scale up the knowledge pretty well, but sometimes that will take you time and resources that maybe you don't have right now. Kubernetes introduce a complexity, right? Like it does introduce complexity. And we, you need to really, really wonder if like you want to push all your developers to learn about it or not. The question that always arises, like, do you want to run one Kubernetes cluster for each of your developers or maybe not? For some companies, that's a good idea. For some other companies, it's not. And sometimes it's mostly about how do you scale up that operation with more and more developer teams? Do you give a cluster to every developer? Yeah. Do you make them manage their own clusters? Like locally, how is the setup? There is a lot of pin. And of course, that takes us always to environment party, right? How similar are the environments that are being used by developers closer to our production environment? The further they are apart, like the more different they are, the more difficult it becomes to make sure that these applications will run in the same way when they are deployed into production environments. And of course, the testing space becomes complicated as well, right? The more complex the application, the more infrastructure it will need. And when you just want to run a single service, like, for example, the pizza store service in this case, you will need some infrastructure components to be running alongside your applications to test it. You can always mock things that will create even more disparity between environments. But you need to make sure that developers have the right tools, the right environments built in, in their tools that they already know, right? Some companies for this kind of stuff, they use Docker compose, for example, so you need to learn how to use Docker compose. And then you need to make sure that the versions of the, you know, dependencies that you have here in the application are the same versions that the ones that you are using in production. That's very, very, very difficult to control. Exactly. And the question is not about, it's not like developers are unable to learn those things. But this is a necessary complexity that we would love to avoid. We would love to enable developer experience that is, that is without those complexities. So how do you go about that? Yeah, so because we are developers, again, we love APIs. As a developer, I know how to create APIs and how to consume APIs. So if you give me APIs, I will use APIs, right? And that's why I wanted to talk a little bit about Dapper, right? Because Dapper provides application level APIs to solve common cloud native challenges. Let's see how this works. Because we already ask, of course, Dali, you know, how our application will look with Dapper. I really like the image, the way it looks. But do not think about Dapper as a centralized thing in there, but think about like a way of obstructing all the infrastructure that your application needs and providing application developers, the APIs to implement different patterns and different functionalities. So how does it work? Because we are in a Kubernetes, you know, conference, I wanted to explain it more for people that knows about Kubernetes. So Dapper works by, you install it in your cluster, you install the Dapper console plane into the cluster, and then what you do is like, you tell Dapper that there are a bunch of services, application services that wants to interact with the Dapper APIs. The console plane will identify these containers and it will inject a side card that will expose APIs for developers. At the same time, platform teams can actually define using configuration files, like, you know, Jamel files into Kubernetes, Kubernetes resources to wire up these APIs to different infrastructure components. So if your application is submitting events or storing data into databases or, you know, key value stores, you can actually configure that to use, you know, Postgres URL, Mongo, or Redis, or a cloud provider service that gives you those functionalities. And the same with Kafka, right? Like, you might be using Kafka, but at some point you're running, you know, in Google and you want to use Google, PubSub, or Amazon SQS, then you can swap the implementations in your production environment. But for the developer, the APIs will remain the same. This is interesting. Oh, yeah, yeah. No, no, yeah. It's interesting because, like, note, for me, I'm less of a Kubernetes native experience, right? It's very interesting because you separate actually the configuring services and infrastructure and using it from your applications, making it two separate problems, two separate roles of people. Exactly, yeah. And also, like, what we do in Dapper is basically because we're injecting a sidecar, we're exposing HTTP and gRPC endpoints for applications. That basically means that any application in any language can interact with these APIs. We also provide SDKs to make it easier, but, you know, you can choose any language that you want for that. And we have different building blocks, right? Like, we have publish and subscribe for emitting and consuming events. We have state management for storing information and retrieving information. And then we have higher-level constructs like distributed locks for cloud native applications, for distributed applications, and even workflows now in the latest release. Also, on the bottom, then, basically, because now you are interacting with APIs, not with infrastructure directly, you can just swap that infrastructure for any cloud provider infrastructure that you have available, or your managed, self-managed infrastructure. So, when you look at Dapper and because we're using the sidecar model, you also get a bunch of cross-cutting functionalities out of the box, like resiliency, security, observability, mostly because you have a sidecar that is looking at what the applications are doing, connecting with infrastructure and taking data about what's happening. But, I've just mentioned, you know, we need to install Dapper into a cluster, then you need to have a platform thing, configuring components, that would actually not work for a local development environment, right? Yes, yes. I don't want to have a cluster on my machine. I don't want to think about installing anything into the control plane of that cluster. I don't want to think about operators. And, for the local development environment, there is this amazing, amazing project called Test Containers. It's not just me saying that. I am paid to say that, but also there is a large community who is... Let me ask, how many people know about Test Containers already? Yes, the job folks mostly. So, Test Containers, for those who don't know, Test Containers are open source libraries that give you the programmatic API to do things with containers. And we are mostly targeting the pre-production use cases. So, you can use... It's in your programming language. There are implementations in different languages, but most popular are covered. We even have Haskell there for you, sir. Very good. Actually, there are a few more. Most of those implementations are community-driven events and Atomic Charger. We are trying to help people get them to the same level for maturity. The most popular ones are very, very mature and stable. And there is the complete experience for you. There are open source Test Containers libraries that you can use for that. There is a free desktop application that you can use for your local setup to make it more efficient and work with the Test Containers by setup. There is a cloud service if you don't want to run containers in your local, local environment. It's a whole suite of solutions. But at the heart of that is, of course, the open source libraries. And they give you the API. I think it's the next slide. They give you the API to do things. There is an ecosystem of... Because it's in the programming language, you can build all the abstractions that you want. You can build yourself or somebody can build it for you. There is a whole ecosystem of modules which are predefined abstractions, small libraries that can give you one or two lines of code that you can define to run a service in the container. If you want a database, you can say, oh, give me Postgres. If you want Kafka, you get Kafka. If you want AWS, you can get local stack in two lines of code. The ecosystem is very, very vast and it's in different languages. There is API to configure the actual containers. You can run anything that runs in Docker Container via Test containers programmatically. There is API to manage the life cycle so you can start-stop containers which is very good for your local environment and tests because you might want to have separate isolated environments. And it's also the convenience API to wire the application to use those things in tests because, well, your service will be spinning up somewhere in the random containers and you need to actually connect to them. It looks very, very natural. In Java, for example, I can say, I can add a library to my project and I can run my, say, I need a Postgres for this pizza application. We need the Postgres so I can say, give me a new Postgres container with that Docker image and I have the whole suite of configuration. Anything I can do with a Docker container, I can do programmatically. I can just type dot in my ID and my ID will offer me, do you want to expose ports? Do you want to override the environment variables? Do you want to override the command for the image? Do you want to put the resources, like how much CPU and memory it has to use and so on. So I can copy files into this. I can configure my database or any other technology that I want to run and then, sorry, and then I can start it and I can get, for example, the connection URL to connect to that database. So for other technologies, for Kafka, for example, this will be also, I will start my Kafka and I will get my bootstrap servers. But it's all programmatic so you can build whatever you want and use it yourself or share it with people in your company or within the project. It also works the same way in other languages. So if I look at the Go version, we predicted that most of people here will be Java and Go, which is good job us. In Go, it will look very, very similar. You add a dependency on the test containers modules and then you say, I would like to run my Postgres and this is my image and this is the configuration and it sits there in your task code or in your application life cycle code. And when this code will run, it will discover a Docker environment a compatible Docker environment doesn't have to be Docker environment. Discover, run the container in it, wait for the container to start and the service to be available for you in the container. We can specify the waiting strategy there. So when the Postgres will tell us that it's ready, it will work. And then we can get the connection strings and we can wire our application to that. And at the end of the run, test containers will clean up the environment so it's repeatable. You can run your tasks again and then again and again and you don't have to lift a finger because it's all there in your code. It will never get stale because it's right in your code. And it's by default sure it was everyone on the team. So it's great developer friendly setup. That's correct. If we look at our pizza application, we have the test which is the separate program. Our test is a separate program. It will start our pizza application. For Java it will be the same process. It will get the test containers libraries, test containers, libraries will start the containers and our application can run in the environment that uses the same technologies as in production but in any environment where there is Docker. So it could be my laptop. It could be your laptop. It could be somebody who was a Windows laptop. It could be my CI solution. That gives us good environment priority and good results for repeatable tests. So how do we wire it together? Yeah. So we because again like Dapper it's mostly focused on you know like deploying on Kubernetes and you need a control plane to work with Dapper so it injects the sidecar and all that stuff. I thought that for developers that's usually very complicated and for a Java developer or even for a Go developer using Docker Compose to configure Dapper it's pretty complicated as well just to make sure that you have like APIs available for you to use. So when I when I looked at test containers I believe that test containers can gives us even like further abstraction right. For database maybe you can say you know start Postgres but for Dapper for the developer itself I don't even want the developer to learn about Dapper itself for how to configure it or just how to use the APIs. If the developer learns how to use the APIs to store data to emit events to consume events they should be able to do their job right. So that's kind of what we did with the you know Dapper and test container integrations which basically does that right like so I have my pizza store in my IDE I just include a dependency for testing in this case I will show it in Java but you can do the same and go and basically what you do is like you start the application and automatically the integration will start the Dapper sidecar with a configuration for those APIs for the local environment right. So if you do this then you are building your application against some APIs that you are using for testing here like a local setup but the APIs are the same when you move the same application code to your production environment and I want to quickly show you this in Java we don't have too much time unfortunately we have like only four more minutes but what I want to show you here is that so my test basically that's my pizza store application I don't know if you can see that in the back hopefully you can I will try to make it a little bit bigger but this is the test of the application right like very simple test it just placed an order by sending an HTTP request to slash order and then it just checks that the order was placed correctly right like not very complicated test to start with but in order to test this I have just a configuration here like a test configuration that basically will start the application run the test against the application and then if everything is okay it will finish successfully but because the application is using the DAPRA APIs for example to store the order into a persistent storage you can see here I have like a store method here in the Java application that it's using in this case the DAPRA Java SDK to interact with the DAPRA APIs just to call this method here right that it's saying you know client save state and I will say the order into a key value store in this case so if you take a look at the test here like the test configuration the only thing that the developer needs to do is just add this annotation of course it's Java so you add annotations and things happen automatically and it says you know this application will use the DAPRA APIs that's the only thing that I need to set up for my application and when I run the test I will be able to use the APIs but because I'm using Spring Boot a framework in Java that allows you to create applications what I can do as well is I can run this command I will make it bigger because I will make it bigger here I don't know if you can see that I will it doesn't really matter the command that I'm running right but I'm just starting the application in what we call like development mode so the application will start in the same like using the same test configuration with all the infrastructure that it needs to work and the test container integration here you will see that it will start actually the DAPRA sidecar right beside the application it will wire it up together so the application can use the APIs so what I can do now is I can go to the browser here and now I'm running my application this pizza store service alone right I can refresh this because it's the same port that I'm using so I'm not using any Kubernetes or anything in here and I can actually go and place another another order in this case because I'm only running the pizza store I'm not I do not have the kitchen service the meeting events I do not have the delivery service the meeting events nothing will happen but I can iterate on these you know on this application pretty quickly because it's running locally no Kubernetes no containers it's just been automatically wired with DAPRA by the integration yeah and if you need you need a larger setup for testing for example you can always mock services with the right number of projects that are available for mocking I think the CNCF currently approach is a my crocs my crocs is how you mock them so you showed a very small we showed you a very small example where there is a little bit more is hidden in the code behind those annotations but there is just I don't know maybe a hundred lines of code right maybe something like this it's not that big of a deal to set up the environment and it gives us two things it will actually more but it gives us the consistent API that we can use in our local during our local development running the application like more research has shown up right it was running locally there is no virtualization I can use all my tools and my application uses the same API and the same approaches it will use in production and it also my testing experience becomes so much better because my tests are self-contained there is no dependency on the like I don't need my platform team to give me like an instance of post-dress that I'm going to share with my colleagues you right I get my isolated environment my tests are self-contained my tests are repeatable and they also because it runs with the same technologies and with the same APIs it gives me the high signal about the how confident I am about the code quality which is which is what I want from the testing spirits yeah exactly and actually like this presentation it's based on the upper-end test containers but these are like very genetic things that you should be looking if you're trying to enable developers to be more productive right having this consistent APIs no matter if you use that or if you use other projects having this consistent APIs for developers to do their work without worrying too much about the infrastructure that they're going to use I think that it's the next step of abstracting away you know cloud providers and a specific infrastructure for your applications having the testing experience is great and also something that we didn't mention that much but it's also like because we are working with code we can start creating libraries that platform teams can start distributing across the development teams in a very simple way we can create our libraries to define what for example is a dapper local environment or what is your company specific environment for developing this specific service and distribute that across different developers and different teams that they need that it also could be you on the project but you will be wearing the platform engineer hat for that for the time so we have that application that it's using dapper and it's using test containers that integration was published like last week it's been announced today like this very kind like a wire how do we wire things for dapper I do believe that this way of doing things allows you to provide a very specific developer experience in this case and also it gives you the idea of you know you can actually start thinking about developer experience at this level right and then from my side the link to the atomic jar blog post about how to enable the same local experience that we showed you with Java but in go applications with test containers I think this would be very very interesting and of course the sites for the projects and if you are willing to do so join the community there is a slag.testcontainers.com to join the test containers slack workspace where you can well talk to the community and figure out things and dapper has a discord channel a discord channel that you can also join to talk to people important in really really really important about the go blog post is that it shows how go developers are used to work so it's we are not changing the way that go developers work we are just extending the things that they have available to use we don't want to introduce them to us we want developers from each different language to do their thing in the way that they are already used to it but just providing the the things that will enable these more complex environments and these more complex setups we did it and then if you have any feedback please the conference asked us to show that QR code if you have good feedback please just fill the survey if you have less than stellar feedback we personally would love to hear it no need to record it there you go they're just kidding just kidding any feedback is welcome we'd love to read that we'd love to make this presentation better thank you very much for coming I hope we have a great conference today