We consider what IaC (Infrastructure as Code) is and why we should invest our time/money into it. It’s going to be a workshop-style talk and as the result, the end of it you will have complete infrastructure as code for React application on AWS written in TypeScript
Infrastructure as Code for React Application on AWS Written in TypeScript
AI Generated Video Summary
This Talk covers infrastructure as code using Terraform and CDK. The speaker demonstrates how to build infrastructure for a React application, including an S3 bucket and connecting to a real domain. They also discuss configuring cache behavior, CloudFront, and remote backends. TypeScript is highlighted as a powerful language for infrastructure as code, and the importance of automation and well-documented code for global-scale infrastructures is emphasized.
1. Introduction to Infrastructure as Code
We're going to cover infrastructure as code. My team at The Zone is changing how fans engage with sports. We have a wide range of infrastructure. To avoid manual errors and ensure scalability, we need to use infrastructure as code. There are two programming paradigms: imperative and declarative. Terraform, an open source software, supports thousands of providers and allows us to manage infrastructure with code, including TypeScript.
Cool. Yeah, as I said, now we're going to cover infrastructure as code. But before let myself and give you a bit of background why we need it. So what's going on?
Cool. My name is Denys Artyukhovic. I'm team lead at The Zone. Originally, I'm from Belarus, now based in London. And at The Zone, we're changing every aspect how fans are engaging with sports, starting from the content distribution to a truly immersive experience when in real time you can see augmented data for the video streams. We are available on more than 200 countries, and various types of devices, including smart TVs, tablets, laptops, and of course like Xbox, PS5, and other game consoles. And I think you can imagine how many types of various infrastructure we have. And my team actually built features which are cross-target. They are available on web and on TVs.
So the answer now, probably obvious, but let's consider like normal flow of developing their applications. So we're starting with the one feature, or let's say service, then new, bright, shiny idea comes to the stage and we have one more feature, and then boom, hundreds of them. And in our case, we can expect changes in our infrastructure even multiple times per day, and I think you can imagine how stressing it could be if everything will be manual, because you need to replicate some manual changes, and what if some of the developers forget to update the documentation? Or what if UI itself has changed on our Cloud provider, like AWS, and we click on the wrong tick box and Facebook is not available for a few hours? So it can be really stress, right? So to avoid this situation and to fix this problem and never been such a problem, again, we need to take advantage of the infrastructure as code.
But before we're gonna start talking about the infrastructure itself, let's consider these two programming paradigms as they are quite relevant when we talk about coding for the infrastructure. On the one hand, we have the imperative, which stands for explicit instructions for literally everything. We usually refer to some bus scripts, and actually, explicit instruction is the biggest advantage of such approach. But at the same time it's the biggest concern, because you need to maintain everything yourself, and it's not really scalable over time. On the other hand, we have the declarative approach, which stands to describe outcome and handle the provider to do the rest of the job, which is way easier and better to scale. So, yeah, again, with the imperative one, you're kind of smart and you're always blaming system that it doesn't work as you expect it, because you wrote so many lines of code. When with the declarative one, you just don't care until smart providers are handling everything for you. And the good news that Terraform actually, it's an open source. Who worked with Terraform before? Let me ask this question first. Yeah. Okay. A few people. Awesome. So, Terraform is an open source software which is originally developed by HashiCorp, and it supports about the thousands of different providers, and it allow us manage our infrastructure with code, and what's more important for today that it also support TypeScript. Or better to say that CDK, which stands for Cloud Development Kit, supports the TypeScript.
2. Building Infrastructure with Terraform and CDK
To implement infrastructure, you previously needed to learn a new language. Terraform's language is not complex, and I believe it's a game changer. In the next 30 minutes, we'll build production-ready infrastructure for a React application, step by step. We'll start by creating folders and installing CDK. Then, we'll use React Create app to create a basic TypeScript React application. Next, we'll initialize the project with CDK-TF, specifying a TypeScript template and a local back end. If you encounter TypeScript errors, add the skip-loop check flag to the Terraform ts-config.
And I truly believe that it's a real game changer because previously, to implement infrastructure, you likely need to learn a new language. With the Terraform HashiCorp language, which is not bad, it's not complex, probably slightly more complex than JSON or YAML files, but you know, we are developers. I really like the power of programming languages and I'm coding for many years, and that's what I would like to create my infrastructure with, and yeah, that's why I think it's a real game changer.
So in the next 30 minutes, what we're gonna do, I mean, probably a bit less, we're gonna build the React, we're gonna build the production-ready infrastructure for our React application, to be honest, for even any JS application you choose. And yeah, we're gonna do it step by step, it's gonna kind of workshop-style talk, you can follow up with the laptops but don't worry if you need to take your time, after the talk right at the end I will share with you all the code samples and there will be a GitHub repo link, so you can follow up later on and I'm pretty sure that this talk will be recorded.
Okay, so we can start. So let me just do this because it's a bit weird. Cool. Can you see my screen? And just a second, I will make it scalable so I can control it. Okay, so I'm really sorry. I just messed things up. But all good now. Cool. Yeah, the first step, what we're going to do, we're going to use React Create. I hope everyone. Yeah. So we're going to use React Create app just to create the basic TypeScript React application and we're going to run this command for this and after this we're going to have this nice and shiny application ready. But so far nothing is related to the infrastructure itself.
Now we're going to start with creating some folders for our infrastructure. And as a prerequirement we need to install CDK. You can install it on the root level of your machine globally or you can install it per project. It's your call. But basically as soon as we have CDK-TF we can create a project folder and start bootstrapping our infrastructure. For this I'm going to use a command which is CDK-TF init. I'm going to pass the template as a TypeScript, similarly what we've done for the React application and I'm going to specify local back end. If you know what local back end means in terms of Terraforms, it's cool. If not, no worries. We're going to cover it a bit later during the talk. After the initialization, you may see such errors related to the TypeScript and the reason for that because I'm pretty sure Terraform is going to address them shortly but so far you need to add skip-loop check because it doesn't really expect that there will be one more TypeScript project in the same project. As soon as we add skip-loop check flag to ts-config of the Terraform, everything will be okay.
3. Implementing Infrastructure with S3 Bucket
We're going to start implementing our infrastructure using the main.ts file. Later, it can be refactored. We add the AWS provider to the CDKTF.json configuration and define our infrastructure needs. The first thing we need is storage, specifically an S3 bucket. We create the bucket with the desired settings, including public read access. After making the necessary changes, we build and synthesize the changes.
And we're going to be able to see that there is a one TS file which is generated for us with Main Stack. It's called main.ts. And this file is basically what we're going to use as a starting point and where we start implementing our infrastructure. Of course, because it is TypeScript, later you can create, let's say, source folder, do structure in the way you prefer, split everything to reusable functions. I'm going to do now everything in the one single file, but later it can be refactored in the way you prefer.
Cool. So before we start, we need to add one Terraform provider. As I said, there are a thousand providers available for you. They are all open source and you can create your own provider. We're going to use AWS provider, so we are just adding it to the provider list in the configuration of the CDKTF.json, and after that, we are ready to crack on. But, now we need to define how our infrastructure is going to look like, what we actually need for our frontend application.
And the first thing which we may need is storage, right? We need to store our application somewhere. I don't know how many of you have worked with S3 buckets on AWS, but it's just a simple storage service which has great availability, 99.99%, which is cool, but for us, what's important, we're going to use it to store our static assets, okay? So, for this, we can import AWS provider and S3 bucket. That's going to be simple infrastructure you can imagine, and it's very straightforward. Because it's going to be production-ready one, later I plan to connect some real domain and that's why I think bucket we can call the domain name just because it's more explicit. We're going to create a provider. You can use any region you like. I'm going to use US-East-1. Just a side note, for your bucket, for example, you can use European region and EU Central-1, whatever. That's absolutely fine but ACM, which we're going to use for SSL certificates later, requires US-East-1 region. It's nothing related to how we're coding the infrastructure, just related how AWS operates. They need it in their requirements. If you're going to create another region, just create the second one later for ACM. Cool. We are creating the S3 bucket, passing just our bucket name, passing the provider. We're telling that it's going to be website with index.html as a root document. We also are specifying access control list as public read, because who cares about security? I'm making fun, so we're going to fix it later. For now, let it be public one. As soon as you made these changes, you just need to build them and you need to run command YARN syns to synthesize those changes. After this, everything will be transpiled.
4. Deploying React Application to S3 Bucket
To deploy our React application to the S3 bucket, we can use Terraform or the AWS S3 command. After deployment, the site will be available at the bucket's URL. However, to make it production ready, we need to connect it to a real domain.
There will be CDKTF out folder generated, which you can go into and run commands in the following order. You're going to run Terraform init. You need this command only the very first time, because we're just starting with the Terraform. After this, you can run a plan. Plan is optional one. It's just to see what will be planned to apply our infrastructure. And after that, you can run apply. And if you do these steps, you're going to see such output in your terminal, which is going to tell you what was created.
You're going to see it on website and point. And now, we can build our React application with the Yarn build and deploy this React application to the S3 bucket. Deployment part is a tricky one. It can be handled with Terraform when you think it is related to your infrastructure. With the frontend world, I would say that it's not tightly coupled with the infrastructure because you're going to create infrastructure. You don't want to expect changes in your infrastructure all the time when you are updating version of React and adding new feature. So, deployment likely will be separate in your CI. So, I'm going to do it now manually using the AWS S3 command. I'm passing the output folder which is built and I'm passing my S3 bucket name which I just used. And, again, I'm specifying ACL as public read. And after this, if you download it, you will be able to see that your site is available on this URL, bucketname.s3. Amazon.AWS.com. And it's also, we can start sharing it with our, I don't know, like friends, QA, SPOs, whatever. But of course, it's not yet production ready, right? At least we need to connect it with the real domain. So, for, yeah, let's celebrate that we have some achievement first.
5. Connecting to the Real Domain
To connect to the real domain, we use Route 53, AWS's DNS service. Users' requests pass through the AWS infrastructure and are intercepted by Route 53, which aliases them to the S3 bucket. We specify the Route 53 zone, create it, and create a record for subdomains, configuring our bucket as an alias. After running the Terraform Apply command and waiting for validation, everything will be created. The domain will alias to our S3 bucket, but it's still unsecure and not production ready. To improve performance, we'll use CloudFront and ACM. CloudFront redirects users from Route 53 to the closest edge location, and ACM issues an SSL certificate associated with our domain.
And now, let's consider how to connect to the real domain. To connect, like to connect it to the real domain, we're going to use Route 53, which is DNS service provided by AWS. And now, our flow will look like this. So, users passing the request, it goes to the AWS infrastructure, which intercepted by Route 53, which is going to alias users to the S3 bucket.
So, to achieve that, we are going to need to specify just a few changes. We're going to specify Route 53 zone, we're going to create it, and we will use our domain host, just because I would like to create infrastructure for the subdomain. And I'm going to create a record, which stands for subdomains, and I'm passing my hosted zone, and I'm passing to the configuration, our bucket as alias, so it means like everyone who gets access to this record will be transferred, will be aliased to the bucket.
So again, we run build things, go to the folder, plan and apply, and now actually, if you're going to run it, we will see that, let me rewind this, I'm just a bit conscious about time, so we will see that there will be an issue at the very last step. And let's check what actually being created. We're gonna go through the AWS console to route 53, we will see that hosted zone is actually created and there will be even a record, so what is failed? The thing is, I did it intentionally. I bought the domain with a different provider because I think it's common use case when you have like domain bought it on different provider rather than AWS, and I need to meet them somehow, so for this purpose I need to copy NS servers which are now generated on AWS and connect them to my domain provider, so my domain provider doesn't have any providers for terraform, so I'm gonna do it manually. You can do it with a terraform too, but yeah, this is a one-time thing, so my domain provider in Russia, that's why you see Russian interface, but as soon as we connect it, we need to wait 5-10 minutes till NS will be updated and now we run the command with the Terraform Apply and this time we will see, let me just rewind this a bit, after the validation which takes, I don't know, like few minutes max, we will see that everything will be created, yeah, one resource created, nothing destroyed, nothing changed, and now, if we try to access this domain, we're gonna see that it aliases to our S3 bucket and we can see our website which is, again, really cool. But it's still unsecure and it's still not production ready as we're storing our S3 bucket somewhere in United States, so probably round trip for our customer is gonna be, like, slow, and we need to take advantage of all edge locations, so we likely want to bring some CDN service, we also likely want to bring HTTPS for the secure connections, so let's do this changes. So for these changes we're gonna use CloudFront and ACM. So CloudFront is a CDN service which is available on AWS. When the ACM, it stands for the Certificate Manager. For us, it's interesting that it's going to issue us SSL certificate which will be associated with our domain. Okay, so let's have a look now at our infrastructure diagram slightly more complex. So the flow will be now that the user starts from the root 53 and instead of going directly to the S3 bucket it will be redirected to the closed edge location. And our CloudFront will be responsible to retrieve objects for caching only in cases when cache is invalidated or if it's like very first attempt to access it and there is no cache yet created. Cool, and ACM will be used for the SSL certificate. So we're creating the ACM certificate like this. We're using the ACM provider. Again, we're just passing the configuration specifying wildcard for our domain host, because I would like to use it for all subdomains in the future, not only for one. That's why there is this asterisk sign. I'm going to create the certificate validation record. It's just one more record for our domain which will be used for validation. And I'm creating the validation itself, passing the ACM certificate and the certificate validation record to it. So, again, we need to create cloud front distribution too. And please don't be scared if you see and think that there are many lines of code.
6. Configuring Cache Behavior and Fixing ACL
I don't understand them completely. It's just the configuration final shape of our state which we're trying to achieve. We're going to cover methods get, head, and options for cache behavior. We'll pass our SSL certificate and make the final change in Route 53. Now, our site is loaded faster and more secure. We need to fix our public read ACL using origin access identity. This is the final production-ready infrastructure diagram.
I don't understand them completely. It's actually very straightforward lines when you know how AWS operates. But if you work with a different cloud provider, you're going to learn them from there. If you don't know them, no worries. You go just to their website of the Terraform stands for this provider and going to read and understand what they stand for. But it's just the configuration final shape of our state which we're trying to achieve.
So, basically, here I'm specifying that default cache behavior will be stands for redirect to HTTPS. We're going to cover methods get, head, and options because we don't I don't think that we need any postal or other methods for our frontend. We're going to set default TTL as a one-day and I'm not going to specify any restrictions or any order to cache behavior. But if you want to specify order cache behavior, it's exceptions. For example, specific folder you want to cache only for five minutes or like you don't want to cache index html at all. You can specify it in the order cache behavior that's what it stands for.
So, we're going to pass our SSL certificate, which we just issued with ACM certificate. And now, we need to make the final change in the route 53. We instead of our bucket name, we're going to pass cloud front distribution domain name. So, route 53 won't be redirecting to the S3 bucket. Now, it's going to redirect to the cloud front distribution and we just changing the name and hosted zone. We need to run again yarn build, yarn scenes, go to the CDK TF out folder around plan and apply. And after apply finished, we're going to see that now, we have the secure connection for sure. But more over, our site is loaded faster. And the reason for that because now, it's available on all edge locations. So, we kind of covered the CDN here. And that's super cool. But you remember, like in the beginning, I said that who cares about the security? Now, it's time to pay for it. And now, it's time to set this up. So, now, we need to fix our public read ACL. And we're going to use origin access identity for it. So, now, our infrastructure diagram will be slightly more complex. But this is the final one. This is production ready one.
7. Configuring CloudFront and Remote Backends
We're going to have route 53 directing to edge locations previously. Now, we're going to have the cloud front which is going to retrieve object for caching. But what's going to change is at this time, s3 bucket is going to have some specific bucket policies associated with this. And this specific bucket policy is going to check that only specific origin access identity things can have access to it. So, in this case, our cloud front should have origin access identity associated to get access to the s3 bucket. And, of course, after this change publicly, our bucket won't be available anymore. To achieve this, we're going to change the bucket ACL to private, create an origin access identity, specify the policy document, create the bucket policy, and associate it with the ACM certificate. We can then remove everything from the bucket and redeploy it, using the default private ACL. The S3 domain will no longer be available, but CloudFront and Route 53 will work as intended. Finally, let's discuss remote backends. Terraform has a concept of backends, which are used to store the output state. There are various options for backends, but since we're using AWS, it makes sense to create an S3 backend. We need to specify a bucket, a key, and a region. Once we've done this, we can run init and choose to copy the existing state to the remote backend.
We're going to have route 53 directing to edge locations previously. Now, we're going to have the cloud front which is going to retrieve object for caching. But what's going to change is at this time, s3 bucket is going to have some specific bucket policies associated with this. And this specific bucket policy is going to check that only specific origin access identity things can have access to it. Okay? So, in this case, our cloud front should have origin access identity associated to get access to the s3 bucket. And, of course, after this change publicly, our bucket won't be available anymore. Cool.
So, to achieve this, what we need to do, we're going to change in a bucket ACL to private. We're going to create origin access identity. And after this, we're specifying the policy document. Again, it's just the configuration which AWS wants us to put. I'm saying here that we want to have access to objects and we're going to have access to get list of this object. And as simple as that, then we just create the bucket policy, passing the bucket ID and policy document itself. And associating with the ACM certificate this origin access identity so our CloudFront is going to have it. Now, we can just for simplicity reasons, a simplest option, just remove everything, what we put to our bucket and redeploy it again, not specifying ACL anymore, and use the default one which is going to be private. And as soon as we've done it, we can check that S3 domain is no longer available. We're going to see this shiny error page provided by AWS by default saying that access is denied. When CloudFront and Route 53 on the other hand are going to work perfectly fine and that's exactly what we were trying to achieve.
And let me congrats you, if you're sweating now as I am, I promise you there are no more infrastructure related things we need to code but let's discuss a couple of them. We're close to the end of this presentation, but I still want to cover remote backends because so far everything what we have done, we have done on one machine and locally and it's not going to work if we start sharing with our teammates. So you may think that we can probably upload our state, Terraform state to, I don't know, maybe even GitHub, but it's a bad idea, I promise you because there will be sensitive information stored, and for this, Terraform has a concept of backends and those backends actually, there are plenty of them. You can use different databases, for example, DynamoDB, you can use S3 storage, you can use Terraform cloud storage, I don't remember how it's called, but there are plenty of options. I think as we stick with AWS, it makes sense to create our backend on AWS, too, and I think this is a good thing to do, and sorry, to clarify, backend is only our output state. It is basically JSON file, which provides information about which resources have been created and what the current state of our infrastructure is. So we're going to create S3 backend. For this we need to pass a bucket. This is actually a separate bucket created manually, so you can pass any bucket. Usually in companies you have like some private buckets which are not available anywhere else. And yeah, we're gonna pass a key, it's our file name, and we're gonna pass region, which can be any. So once we done it, we need to run init, and this time when you run it in your terminal, you're gonna see that it asks you, do you wanna copy existing state to remove backend.
TypeScript and Infrastructure as Code
TypeScript is more powerful than hash core configuration language, providing auto-complete, typings, and other advantages. It allows for better code structuring and sharing, making it relevant for both frontend and backend developers. Infrastructure for monitoring tools like New Relic and Sentry can also be managed with Terraform. Note that while Terraform is mature, CDK is still in beta. Code samples and additional resources are available in the provided repositories.
And if your answer will be yes, everything will be copied over to the S3 bucket and will be removed from your local machine. Cool, now let's cover why we use TypeScript. Why do you use TypeScript for infrastructure as code? I think, yeah, it's pretty cool that there is no new language to learn, even though that I mentioned previously, hash core plan configuration languages is not that bad, but most of us know TypeScript and why we need to bring anything else. And moreover, TypeScript is for sure way more powerful than hash core configuration language. We have auto-complete, we have typings, we have all mature language advantages. You can think about methods you have for, map, reduce, whatever, and cycles, structuring with different models. You can't really achieve it with hash core configuration language. You need to store everything in one folder and there is no clear connection what is referenced to what, and in my opinion, it's a complete mess. But now we have more options for code structuring and new ways of sharing and here I'm talking about previously we were able to create Terraform modules or plugins separately, but there should be complete things and they are kind of detached from the frontend completely. Now we can use NPM and share our code with NPM, and we can even implement a test for our infrastructure too. Plus, I just want to highlight, because it's really important, I mean, I tried to make this talk focus on the frontend devs because I see that many backend devs knows about the concept of infrastructure as code when it's not exactly so when we're talking about the frontend world. But I think it's pretty relevant for both worlds, not only to create the infrastructure for your application itself, but also infrastructure for your monitoring. For example, you have New Relic and you want to specify some alerting there or create dashboards, or let's say you have Sentry for this purpose. Again, everything can be managed and in my opinion should be managed with infrastructure as code providers, in this case, let it be Terraform. So you can handle incident management with pager duty and again create the infrastructure for this with Terraform. Just a side note, it's still like a CDK, Terraform itself is quite mature already used in production around the world, but CDK, not yet. It's in a beta stage at the moment so you may expect some changes in the CDK itself, so please be careful about that, and yeah, it's not gonna be fair not to mention this.
And now, as I promised, everything, all code samples are available in this repo you can see now on the slide. I tried to follow during Comet history in the same way as I presented, so you will be able to follow up this talk. And thank you so much, that's it, and there is one more repo, Terraform TypeScript Frontend Infrastructure, which has slightly more advanced structuring and a bit more samples, so if you're interested you can check it out too.
And now I think we have Q&A session if there's still time, yeah? You're welcome. Thank you. Yes. Well, take a seat, we can chill now. Would you like something to drink? Oh, no, I'm good. I will clap for the remote audience, they are probably clapping at home, and... yelling at their screen sounds a bit negative, but in a positive way. So, I want to jump into the questions, and as a reminder, you can still ask questions if you're here, I'm also using Slido, and at the end Denise will select the best question, and we will give a React Advanced T-shirt to the winner. So, the first question is from Bruno Palino, static site infrastructure is awesome, but how about when you need actual servers and application deployments with databases, can you handle all this with Terraform? Yes, absolutely, I mean, this is what Terraform stands for, like everything is handled with this including databases, including various infrastructure you can just imagine for your microservices or monolith applications or whatever, so I think it's quite popular among all DevOps and backend engineers and we use it quite extensively. Awesome, okay, the next question is from Anonymous, so Anonymous will not be getting a T-shirt, we can, oh, this is incorrect, this should not be here, I'm reading the questions out loud that should not be questions.
Discussion on Infrastructure and Global Scale
Most of our infrastructures at Dazone are created with Terraform, but we use Azure Corp Configuration Language instead of TypeScript. We are a global company with millions of customers, so automation and well-documented code are crucial for us.
So for the examples you showed us, is this all stuff that you are using at Dazone also? Yeah, for sure, so we actually, like to be fair, most of our infrastructures are created of course with Terraform, but we use Azure Corp Configuration Language rather than TypeScript, we're starting adopting TypeScript but as I said it's like still in beta stage, so you need to be careful about this and you need to remember about concerns related to the maintainability of it if there will be some significant changes related to it, so should be a pin call.
You are quite a global company and any change is a big change I guess and it's really hard to test stuff on your scale. Yeah, absolutely, I mean we are available for millions of customers around the world, so for us it's like increasingly crucial to automate everything we can and be well documented with code so let's put it so.
Alright, since we have no more questions at this moment I think we'll wrap up the Q&A session or I will refresh if there have been any questions in the meanwhile. If I would get any data. Sorry for everyone who was online and get mixed audio, it wasn't from my laptop, something happened. Yeah, it's fixed in the first few minutes. So my data is really bad here in London. And I need to moderate the questions before they show up there and there. Oh, no worries. And I have no data. But, yeah, so Deniz, thanks a lot. And we're going to go to our next speaker then. Yeah, thank you so much.