Streamline Building and Deploying Containerized Applications - AWS Innovate

· ·30 min watch

I gave this talk and demo for AWS Innovate. I introduce the basics of infrastructure automation with infrastructure as code, and then introduce and demo to different abstraction tools for working with infrastructure: AWS Cloud Development Kit (AWS CDK), and AWS Copilot

 

Transcript

Hello, everyone. My name is Nathan Peck, and today, I’m going to be talking about how you can streamline, building and deploying containerized applications on AWS.

So, to start out with this, I wanna talk about the different levels of infrastructure deployment. Different companies start out at different places in their infrastructure journey.

slide4

I remember when I was working at a startup, before I joined AWS, we started out at where I’d like to call Level 0 or creating infrastructure by hand. And this is how a lot of folks start out with deploying applications on AWS. Different engineers are clicking around in the AWS console dashboard. They’re clicking all those buttons, entering, typing information on the AWS console to create different resources on the AWS account.

This works out fantastically when you’re first learning AWS. But there are a few downsides to this, mainly because it becomes hard to make sure that you’re doing the same thing every time. You might have one engineer who’s clicking this button, while another engineer is actually clicking an entirely different button which is interfering and creating differences in the infrastructure.

So as organizations grow they tend to move on from that manual clicking around in the console to imperative infrastructure as code.

slide4

This is where you create a code file which contains the commands necessary to call the AWS API usually using software development kit for AWS, and create infrastructure on the AWS account automatically, using this deploy script. This is a little bit better because now, you can have different engineers working on the same deploy script that actually modifies infrastructure as code.

But it’s a little bit challenging. Writing that code is a difficult process because deploy scripts have to account for a lot of different things that could happen. Maybe a deployment fails, maybe a resource fails to create, or there’s a rate limit on how many times and how fast you can actually create different resources on AWS accounts. So, you have to deal with all these different sort of scenarios that pop up as part of creating an infrastructure.

So, the next level beyond that is declarative infrastructure as code.

slide4

And so this is where the true magic of streamlining your infrastructure deployment begins. The idea behind declarative infrastructure as code, is you can create a description of the infrastructure that you would like to have created. Typically, it’s a yml file or some type of text document, and you pass that off to a intermediary tool, such as AWS CloudFormation or HashiCorp Terraform, which then calls the AWS SDK on your behalf in order to create infrastructure on your AWS account.

slide4

So…to better explain how this works and what that means, I like to compare infrastructure as code and declarative infrastructure to a shopping list. So, imagine if you had a professional shopper and you’re able to tell them, “I need a dozen eggs, I need a carton of milk, I need a carrot, I need a loaf of bread.”

They’re going to do the job of looking inside your refrigerator, seeing that you already have dozen of eggs, but you do need that carton of milk, a carrot, and bread. They’re gonna go out and they’re gonna shop for those missing items. And as a result, then you’re finally gonna get your grocery delivery back.

But you didn’t have to do any of that work of like actually checking inside your refrigerator, or going to the store and buying things. So, the idea behind infrastructure as code is that you start off that shopping list, you pass it off to the infrastructure as code provider, and then you get your AWS resources back.

So, here’s how that ends up looking.

slide4

I’m going to show a snippet of AWS CloudFormation yml here because that’s one of the ones that is AWS native. And so here you see we have a list of resources to find. And inside of that list, there is an S3 bucket. And we’ve defined some properties, such as saying that the public is able to read from this bucket.

slide4

Now, if I modify this grocery list, so to speak, by adding another bucket to the list, then what’s going to happen is CloudFormation is gonna notice that there is a new item on the shopping list and it’s going to go out and it’s going to create that extra S3 bucket for me. As you can see, it becomes very easy for me to list out all the resources on my application needs and then rely on CloudFormation to call the SDK on my behalf and create- and make sure that everything in my shopping list is actually there. Now, this does get a little bit challenging though as you get to larger and larger and more complicated applications, particularly, containerized applications.

And so this is why I want to introduce the level 3, which is infrastructure as code abstraction.

slide4

The idea behind infrastructure as code abstraction is that you have another layer between you and your infrastructure as code. So, developers, rather than writing that grocery list manually, they can talk to AWS Cloud Development Kit, they could talk to AWS Copilot, or another abstraction tool, which then creates the grocery list, so to speak, for AWS CloudFormation. And then CloudFormation goes out and creates those resources, using AWS API and SDK. And the end result is you have your organization’s infrastructure.

slide4

So, to put this once again into simple terms, I like to compare these abstraction tools to ordering food at a restaurant. So imagine, if you go to the restaurant, you don’t expect to give the restaurant a grocery list of things to shop for, you’re going to give them a higher level goal like, “I like to eat this tasty steak dinner.”

And they’re gonna out and decide what ingredients are necessary to actually cook that steak dinner for you. They’re gonna do a shopping for you and they’re even going to cook that meal for you and give you back that meal that you asked for.

So the idea behind these infrastructures as code abstractions is that they are like this restaurant that goes out there, figures out which AWS resources are necessary to create what you’re trying to deploy, goes out, creates them on your AWS account, and then even can help you set them up and configure them so they’re production ready.

So I wanna introduce two different tools for doing that, and you saw them on a previous slide when I showed AWS Cloud Development Kit, AWS Copilot. I want to talk about AWS Cloud Development Kit first. So, one of the typical and most common things inside of a Cloud infrastructure deployment is a Virtual Private Cloud or VPC.

slide4

And if you’re familiar with Cloud concepts, this is a very basic underlying networking fabric which allows all the different resources you’re deploying to talk to each other. But it’s a little bit challenging to configure, especially if you want high availability and you want to have a resilient network. So here, you can see there’s a lot of different resources that are part of this VPC.

There’s internet gateway. There’s NAT gateways. There’s different subnets and different availability zones. There’s the VPC itself.

And there’s also, not shown on this diagram, but if you’ve set up one of these before, you know that there’s a lot of route tables that define the configuration by which traffic goes from one subnet to another, and it can actually be routed around inside of that network.

slide4

So, if I was to define this VPC by hand, in infrastructure as code, it actually takes me 270 lines of CloudFormation in which I’ve shown here. It is too small to read, but [chuckles] there’s 270 lines there of configuration to define all the different resources and the specific subnet, IP ranges, and everything necessary to make that particular VPC work.

And that’s a little bit challenging to create by hand, especially if you need to create that multiple times because it’s explicitly describing every single aspect of VPC in detail. And I don’t necessarily care about all those details once I’ve set up 1, 10, 100 different VPCs.

So, the idea behind AWS Cloud Development Kit is it gives you a higher level API that you can use to define all these underlying settings because it has smart defaults. They understand your higher level of intent for what you’re trying to create.

slide4

So, I can create that same set of resources, that 270 lines of CloudForrmation, using one line of AWS Cloud Development Code. All I have to do is instantiate a new instance of the class ec2.Vpc with the parameters maxAzs: 2. It will go out, it will automatically set up this highly available VPC that spans two availability zones, has net gateways inside of it, it has all the things that are necessary for a production ready network.

Now, this also goes beyond just the underlying cloud resources up to your application resources as well.

So, one of my favorite features of CDK is its ability to tie into your local development experience as well.

slide4

Here, for example, you can see a feature of the AWS CDK ECS pattern for building a container image and shipping it to production. So, if you’ve built a container image before, you know that you have all your code, your libraries, your different binaries on your local developer laptop. But in order to ship that to production, you’ve got to package that up into a Docker image. You’ve got to upload that container image into a registry that has to exist. And there’s quite a few steps involved in that process.

Well, all those steps are actually encompassing this one command here where I say: ecs.ContainerImage.fromAsset() And I specify a local directory there, apps/myapp.

So, what’s gonna happen is, CDK is gonna go inside that directory, gonna find my docker file, it’s gonna automatically build a container image, it’s gonna create its own unique, elastic container registry for storing my container image and upload it to that registry.

That also extends to the actual patterns for turning that container image into a deployment.

slide4

So, here you can see one of the patterns we’ve built called ecs-service-extensions for deploying a container that’s been built by CDK as a service. We can see that we have this very simple high level classes, such as Environment and ServiceDescription and Container, where you can build out an environment, build a service description and add your container to that service description, and then deploy that service description as a service inside of an environment.

So, I’ll demo this in more detail later, but I wanna show an example of what CDK looks like when you’re using these higher-level interfaces as an abstraction for creating an infrastructure.

slide4

So, if you’ve turned on different features of AWS platform, you know that certain things like X-ray or Cloudwatch can be a little bit challenging to set up at times.

Well, with CDK, all you have to do is add different components onto your service using this very simple SDK of service that add, and then you’re adding on a particular feature of CDK. And it will enable that feature inside of your service and do all the setup and plumbing, all of that Cloud information writing for you in order to turn on that particular service. Then again, that gets deployed, and you can even build your own extensions that turn on or enable different services for the underlying container infrastructure.

So, CDK is one way of doing it, especially if you are more into the coding side of things. CDK is designed for folks who likes to deploy infrastructure but they like to do it using a programming language. Another option is AWS Copilot.

slide4

And AWS Copilot is a command line tool. So, it’s designed to be simple to get into because you can just type copilot init and it starts asking you some questions like: “What type of application would you like to deploy?”

Which I can then choose load balanced application. It will go in and it’ll explore your code tree and find a Dockerfile and suggest, “Would you like to deploy this api/Dockerfile as a container service?”

The general idea behind AWS Copilot is it give you these command line tools for solving several different phases of your application.

slide4

The first phase is building and deploying your application. It has a walkthrough process where it will explore, come up with some sensible defaults based on Docker file that it finds, and suggest different infrastructure patterns you may want to deploy such as a load balanced service. And then, it’ll do everything else for you. It’ll create that, write that Cloud formation for you and deploy the infrastructure onto AWS account.

The second phase is when it’s time to monitor and observe the application. So, AWS Copilot gives you really helpful helper commands that you can use to do things like tail the logs in your production environment, or even get a command line shell inside one of the running containers inside of your Cloud environment so you can run commands directly inside that container.

And the last phase of AWS Copilot is it helps you automate things. So, this is where we really get into the streamlining aspect of containerized deployments. It will help you set up an automated delivery pipeline where all I have to do is type git push and it will start building and deploying my service in the background.

Now, I talked about all these different features and talking about them is great, but I’d like to actually show these features in action because I think that’s a lot more fun. So, I’m going to transition over to the demo now, and we’ll see these things in action on my AWS account.

Demo

View raw demo transcript

All right, so, now for the demo, you can see that I’m right here inside of my IDE where most developers spend most of their time. And I’ve got some code here for a simple application which uses DynamoDB. And it’s really no GS. So, if you look at this code and understand the GS code, no requirement if you don’t, but I’ll explain what this is doing. It’s actually talking to a Redis deployment and… Wait, this [inaudible]. It’s this one. It’s talking to DynamoDB and it is implementing a simple hit counter. So, I toss it, the DynamoDB table and increments a counter inside the table to keep track of the number of hits to a particular website. So, you can imagine this might be a simple like view counting service they might implement. So, I’m gonna deploy the same application two different ways using AWS Cloud Development Kit and using AWS Copilot. So, I’ll start out with AWS Cloud Development Kit because that was the first one that I talked about. And to explain how kind of all development kit works, I’m gonna show first the infrastructure as code and how that’s implemented inside of Cloud Development Kit. So, you can see very similar to the pattern that I showed in the slides. Some typescript code is very similar to the code for the service itself. And then, they’re both based on JavaScript. And you can see that I define an application and a stack. I can create an environment and a service description. And then I add my container to that service. And all I have to do in order to containerize that application and deploy it, is say, ContainerImage.fromAsset (‘app’), where app is the name of this local directory app that has my code inside of it. Now, I have supplied a Docker file here, which describes, you know, what version of node to use, Node 18, and how to build this application by running npm install. But this is all that I needed in order to containerize the application. Everything else is going to be done by Cloud Development Kit as I do my deployment. You can see that also in Cloud Development Kit, I’m able to define some things like the DynamoDB table itself that my application is built against. You can see I defined the keys and the billing mode for it. And I’ve also even attached a load balancer to the service so that way I can send a public traffic to it. So, let me show you how this works when I, when I’m actually going to do the plumbing. I want to make a little change to the code and I’m going to run over here in my command line and run cdk synth, which is the, the command for generating a infrastructure as code version of the particular application that, that I’m looking at. And I’m actually gonna write like this. So, while that, while that’s running, I can show in the, the, the command here the, the output that it had created. So, you can see that there are actually over 1,000 lines of infrastructure as code here that describe this particular application as DynamoDT-DynamoDB table, its deployment and everything that’s necessary. Now, if I run one of the other commands which is diff… You might be familiar with the idea of git diff, which shows you the differences in 2 versions of code. Well, CDK also has the concept of a diff which will show you the difference in what it is actually deploying on your AWS account. So, here you can see, because I’ve updated me and changed my code, the text is going to be updating the application image when it deploys it. So, now, I can run cdk or npm script deploy to kick off this actual deployment and deploy these assets on to my AWS account. So, while this is running, I can show in the AWS console what’s happening. And you can see that it’s actually building my Docker image here and uploading it. And that starts creating a CloudFormation change set. So, this is where behind the scenes has created the CloudFormation for my service. It’s uploaded via the asset, and now, it’s handing off control to CloudFormation to say, I’d like you to take this grocery list or, so to speak, of resources and resource changes that I’ve created and deploy that. So, if I switch over to my AWS console, we’ll actually be able to see resources changing on my AWS account. And if I can see that inside of the CloudFormation console. So, if I go to CloudFormation, I’ll see that this particular stack hit counter demo is now in progress updating. And I see under resources that this AWS ECS service is now- has an update in progress. So if I go to the ECS console, I’ll be able to see the progress of that deployment as it pulls out a new copy of the application and a container to my service. And that would be this one right here. And sure enough, inside the service, we see there’s two tasks running because it’s currently rolling out an update to a service. And I’ll go in here and see. Yep, it started 124 seconds ago. The previous one was started one hour ago. That was when I was setting up for this demo earlier today. And we will see that it is actually rolling out a new revision so you can see what – from revision 5 to revision 6. So all I had to do was actually make a change to my code and run cdk deployed, and it handled the entire rest of the process of building new image, uploading it and initializing that, that deployment. So I like Cloud Development Kit because it has all this rich capability for giving you a control over all the different resources and manual control over the different resources you want to create in CloudFormation such as [inaudible] table. But programming isn’t for everyone. Sometimes, you want to have a difference between the operations team and the application development team and you don’t necessarily have the same folks who are working on the application code that are the same folks that are deploying the infrastructure. So I want to introduce, Copilot is another alternate way to define your application. And Copilot is designed to give you a simplified deployment definition that is also yml. So it’s very similar to what you might have seen inside of a confirmation file, but its design have a more simplified API, which you can see here, there’s very few settings here, just the image to build and its source, the port, the CPU, memory and how many to deploy. So meanwhile, CDK over here has finished deploying, so I can actually send a command to hear and see how many hits have hit my website. So I can see here 207,548, 549, 550. So the CDK deployment has, has completed. Now, I want to show this very same process with Copilot. So I switch over to Copilot. I want to show the Copilot commands that are available here. You can see there’s top-level commands like in it, which is initializing a new deployment, application, environment service. And even for jobs, if I have like a one-off job I want to run, I can define all of these using this very simplified manifest format and let Copilot do the rest of the job of doing the deployment. So I’m going to kick off another deployment using Copilot this time. Once again, we make it- we’ll change the code so that way there is a different to actually deploy. And all I have to do is say Copilot deploy. And one of the things you’ll notice as this deployment kicks off is that Copilot is more aware of the containerized environment. So whereas Cloud Development Kit is a more general purpose infrastructure as code system, a Copilot is very focused on containerized deployments in particular. And so you’ll see that- you’ll see right away a few differences like this pretty coloration of the Docker output compared to the other output. And you’ll also see, if I drag this out [inaudible] you’ll see a better description of the actual progress of what’s happening during a deployment because Copilot is looking at the actual infrastructure that’s being deployed. It understands the fact that this is an ECS appointment. So you’ll see that it’s actually showing me right here in the command line the progress of rolling out. So I see that there is one active deployment which is running one copy of my container, but there’s a new version of the application which is now the, the primary deployment. And there’s a desired, count of wanting one copy of that container image, but what’s currently running is one copy of the other container and there’s a previous version. So we’ll see. I’ll leave this running while I show the rest of the stack. And you’ll see, gradually pop in. First, it’s pending. So the new version of the application is now pending as it starts up. This is while it’s downloading the container image and beginning to run health checks at it. We’ll see it go from pending to running and then it will then shut down the previous active version of the application. Now, one of the things I want to show as part of this, while this is running in the background, is one of the cool features of Copilot which is addons. And the idea behind addons is that you can combine the best of both worlds. You can have infrastructure as code, written CloudFormation. And you can have this simplified command line tool which builds and deploys your application with minimal commands. So here I’ve created an addon which was the actual DynamoDB table that I wanted to deploy. And because I’ve added this into a subfolder, Copilot is actually going to go ahead and deploy this DynamoDB table and even take the output value here, which is the name of the DynamoDB table, the dynamic name, and inject that into my container automatically, making it very easy. And I can actually initialize that by just running a simple command called Copilot storage in it, which I could show you if I do. So you can see, if I type Copilot storage in it, I’m in the – I don’t have my, my- I think setup in that particular journal. Okay. So this is still running, still deploying. While this is running, I also want to show the pipeline aspect. So one of the things that Copilot deploys automatically is a pipeline that self-initializes and uses Copilot on the server side to actually deploy your application. So I’m driving this deployment right here from my local machine. But as you can see, it’s tying up my terminal this entire time while it’s waiting for this deployment to happen. It’s waiting 162 seconds so far while it waits for the new container to pass health checks and wait for the old container to shut down. But that’s not ideal if I’m a developer who wants to build and iterate fast on my code. So, one of the things that Copilot allows you to do is set up a pipeline automatically that uses AWS code pipeline in code deploy and could build to do the containerized build and the update on the server side instead. So that way, all I have to do is run a git push command, and it kicks that off. So I want to show you that process as well as this deployment finishes up over here in terminal. Looks like it’s almost done, and sure enough, we have a deployed service now and I have a URLfor it. So I can also send a curl command to that and see the hit counter counting up these different hits to the website. Now, for the, for the pipeline, I’m going to show the pipeline status first to show how Copilot has commands built into it that allow me to see the different stages of the pipeline, such as grabbing the source, building it and deploying it. But I want to show what this pipeline looks like in action in the AWS console as well. So what I’m going to do is I’m going to make a git commit to save my changes that I’ve made. Minor change to comment. And after I’ve committed that, I can push it to my, to my repo, and that’s going to kick off a change now on the server side rather than on the client side. So if I go into code pipeline now on the AWS console, I’ll be able to see my pipeline that looks out by Copilot deploying my application. You can see, it actually says this change is in progress here. So what it, what it did was it, it picked up that code change I made just now, pulled it in and it started kicking off a build here this time on the server side. So once again, you’ll see, it’s not tying up my command line anywhere. I can be making code changes while this happens [inaudible] in the background. So this is a little bit better for when you have multiple developers who are working together on your infrastructure. And normally, setting up these pipelines can be a little bit of a challenge, can be a little bit of a hassle, but that’s not a problem when you have Copilot. They can set up and configure that build for you automatically. And you’ll be able to see that the build is happening on the server side and even see the logs of it happening on the, on the server side. As it does, that same build container-container build, but this time on the server side, which is not using up any of my local developer resources. So hopefully, this gives you an overview of how these tools work. If you’d like to try them out, I highly recommend going to the AWS Copilot documentation here and clicking get started. We have some great guys here about how to deploy your first container using AWS Copilot and from how to install Copilot all the way through to deploying that very first application using Copilot. So this is a great way to get started with containers if you haven’t done anything with containers yet. Now, if you want to use CDK, if you have a little bit more experience and you want to have more control over infrastructure, I highly recommend, if you’re deploying containers, to try out CDK with ECS service extensions.

 

You can also download the PowerPoint presentation that has the source slides for the presentation.