Set Up Kubernetes Deployment
Prepare an app's backend for deployment with Kubernetes!
Introduction
⚡️ 30 second Summary
Welcome to part TWO of your four-part Kubernetes with AWS series.
You've learnt how to launch a Kubernetes cluster in the previous project.
Now, picture this: a team member just developed an entire application and shared the GitHub repository of the app's backend.
Are you ready to pull the app's backend from GitHub and prepare it for deployment with Kubernetes? Let's go!
Want a complete demo of how to do this project, from start to finish? Check out our 🎬 walkthrough with Natasha 🎬
In this project, get ready to...
- 📥 Clone a backend application from GitHub.
- 💿 Build a Docker image of the backend.
- 🗃️ Push your image to an Amazon ECR repository.
- 🤯 Troubleshoot installation and configuration errors - as a PRO student, get ready to face errors head-on and push your skills to the next level.
- 💎 (Secret Mission) Dive into the backend code on GitHub.
If you're up for a bit of a challenge, quiz yourself on the key concepts up ahead in this project.
This project is part of a series:
Before we start Step #1...
Before we get started, it's important that you know what we're trying to do today...
This project is part TWO of our Kubernetes series - have you completed Project One (Launch a Kubernetes Cluster)?
Yes, I deleted my resources
Perfect! Welcome back to the Kubernetes series, and it's awesome to have you here again.
See you in 🛠️ Step 1!
Yes, I kept all my resources
If you've completed all the previous projects and kept your resources, you can skip the setup steps.
TIP
If you can, we recommend doing all the questions and screenshots in the set up steps anyway. It'll make your project documentation look AMAZING!
Jump straight to 📥 Step #2!! See you thereeeeee.
Nooo, I haven't!
Haven't tried those projects yet? That's okay! You can still do this project 👌
Give yourself some extra time to go through 🛠️ Step #1 slowly... You'll make the most out of this project if you go slow and build a strong understanding of Kubernetes and EKS over the first few steps :)
Set up EC2 and EKS
Let's kick things off by setting up our environment! We'll launch an EC2 instance, which is where we'll send commands to EKS and other tools. Then, we'll create our EKS cluster.
What is EKS?
Amazon EKS (Elastic Kubernetes Service) is a service that helps you run Kubernetes on AWS.
Setting up Kubernetes from scratch can be quite a time consuming and complex thing to do, because you'd need to configure Kubernetes' networking, scaling, and security settings on your own. Amazon EKS handles these tasks for you and helps you integrate Kubernetes with other AWS services.
If you get stuck in this step, check out the first project of this Kubernetes series for a detailed explanation of each part.
In this step, get ready to:
- Launch and connect to an EC2 instance.
- Set up eksctl and your instance's AWS credentials.
- Create an EKS cluster.
Log into the AWS Management Console as your IAM Admin user.
Launch and Connect to an EC2 Instance
- Head to the EC2 console.
- Check that you're using the AWS Region that's closest to you.
- Click Launch instances.
- Name your EC2 instance nextwork-eks-instance
- For the Amazon Machine Image, select Amazon Linux 2023 AMI.
- For the Instance type, select t3.micro.
- In the Network settings section, we'll keep the default security group for now.
Extra for Experts: Is using the default security group security best practice?
We wouldn't do this for production environments or long-term use. For now, the default security group makes it easier to use EC2 Instance Connect when we connect to our EC2 instance.
If we don't use the default security group, we'd have to manually edit our instance's inbound rules to let in Instance Connect's range of IP addresses, which is different depending on your AWS Region.
Feeling up for a challenge? Try editing your security group settings to make it more secure (while letting you use EC2 Instance Connect later on). If you get stuck, ask the NextWork community!
- Select Launch instance.
- A pop up appears! Can you tell whether you need a key pair?
- Select Proceed without a key pair (not recommended).
- Select Launch instance.
- In your EC2 console's Instances page, select your new instance.
- Select Connect. Welcome to EC2 Instance Connect! This is a convenient way to access your instance directly from your browser.
- Select Connect again in your EC2 Instance Connect page.
Install eksctl
What is eksctl?
eksctl is a command-line tool for working with Amazon EKS.
We're using eksctl because it's one of the simplest ways to create Amazon EKS clusters. You end up running much fewer commands compared to using AWS CLI, because eksctl detects the resources you'll need and automates the environment setup e.g. creating networking resources.
- Run the following command in your EC2 instance's terminal to download, extract, and install eksctl.
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv -v /tmp/eksctl /usr/local/bin
- Verify that you've installed eksctl:
eksctl version
- You should spot a version number in the terminal output.
I don't see a version number
Try running command to install eksctl again. Make sure there aren't any errors in the terminal response.
Stuck? Ask the NextWork community!
Set up IAM role for your EC2 Instance
Let's create a new IAM role for your EC2 instance! If you've done this before in the first project of this series, you might still have it in your AWS account...
Do you need to create a new IAM role?
TIP
If you're not sure whether you've got the IAM role, search nextwork-eks-instance-role in your IAM console's Role page.
I need to create a new IAM role
- Head to the IAM console.
- Select Roles.
- Select Create role.
- Under Trusted entity type, select AWS service to tell AWS that we're setting up this role for a AWS service (Amazon EC2).
Why do we need to set up an IAM role?
Your EC2 instance starts off as a blank slate, so it doesn't actually have the permission to do anything in your AWS account yet! Your instance would fail to use eksctl to create any EKS clusters.
You need to give your instance the permission to work with AWS services, and you can grant this using roles.
- Under Use case, select EC2.
- Select Next.
- Under Permissions policies, we'll grant our EC2 instance AdministratorAccess.
Extra for Experts: Is granting AdministratorAccess best practice?
Great question! Granting AdministratorAccess is powerful but not ideal for long-term use. We’re using it now because we don’t know all the services your EC2 instance will access for this project yet.
In a real-world scenario, you’d follow the principle of least privilege - giving user/services/apps just enough permissions for the job to minimize security risks. In a real-world scenario, you’d follow the principle of least privilege - giving user/services/apps just enough permissions for the job to minimize security risks.
- Make sure the AdministratorAccess option is checked, and select Next.
- Let's give this role a straightforward name - nextwork-eks-instance-role
- Enter a short description:
Grants an EC2 instance AdministratorAccess to my AWS account. Created during NextWork's Kubernetes project.
- Select Create role.
Great! Your new role is born. Now let's attach this role to your EC2 instance.
I already have the IAM role
Perfect! If you already have nextwork-eks-instance-role, you can head straight to attaching the IAM role to your EC2 instance below.
Attach IAM role to EC2 instance
- Head back to the Amazon EC2 console.
- Select Instances from the left hand sidebar.
- Select the checkbox next to your nextwork-eks-instance EC2 instance.
- Select the Actions dropdown, and then Security -> Modify IAM role.
- Under IAM role, select your new nextwork-eks-instance-role role.
- Select Update IAM role.
Create EKS Cluster
- Back to EC2 Instance Connect, run the following command to create your EKS cluster.
eksctl create cluster \
--name nextwork-eks-cluster \
--nodegroup-name nextwork-nodegroup \
--node-type t3.micro \
--nodes 3 \
--nodes-min 1 \
--nodes-max 3 \
--version 1.33 \
--region [[AWS_REGION="your-region-code"]]
- Check: Have you replaced your-region-code with your AWS region's code?
- Creating your EKS cluster can take some time (around 15-20 minutes), so let's do something else in the meantime...
Pull the Code for your Backend
Now that our EKS cluster is spinning up, let's find the app backend that we want to deploy. Your team member has pushed the backend code into GitHub repository, so let's start there!
What is 'backend'?
The backend is the "brain" of an application. It's where your app processes user requests and stores and retrieves data. Unlike frontend code, which is what users see and interact with, backend code works on the server side (i.e. in the background) to make sure your app behaves as expected (e.g. loads a new page) when a user does things like clicking on buttons.
In this step, get ready to:
- Install Git.
- Make a copy of application code from GitHub.
- While your EC2 instance is busy with creating your cluster, head back to the EC2 console in a new tab.
- Select your EC2 instance nextwork-eks-instance-role, and select Connect again.
- Start a new EC2 Instance Connect session with your instance.
Woah, I can run two Instance Connect sessions with the same instance?
It's true - you can open multiple SSH sessions to the same EC2 instance at the same time.
This can be super helpful when you want to multitask or monitor logs while running commands in another session. And don’t worry, it doesn’t pause any progress in your other windows.
Let's clone our team member's backend repository.
What does cloning mean?
When we say "clone a repository," we mean creating a full copy of a repository's code stored remotely (in this case, in GitHub) to your machine (in this case, our EC2 instance).
This way, you get access to all the files and code without having to manually copy and paste.
If you're new to Git and GitHub, check out our Connect a GitHub Repo with AWS project.
- In a new tab, visit your team member's GitHub repository.
- Select Code to reveal the instructions for cloning their repository.
- Copy the HTTPS URL.
- Head back to your EC2 Instance Connect tab.
- In the terminal, run the command to clone your team member's repository. Replace your-github-url with the HTTPS URL you've copied:
git clone [[GITHUB_URL="your-github-url"]]
- Whoops! You'll probably get an error here...
What is this error about?
The terminal response "Git command not found" means you don't have Git installed in your EC2 instance. You'll need to install it first to clone a GitHub repository.
Tip: It's helpful to note that "command not found" typically means you haven't installed the tool you're trying to use!
- Install Git:
sudo dnf update
sudo dnf install git -y
- Verify you've downloaded Git by checking for its version:
git --version
- Configure Git by running the command below. Make sure to replace the placeholder values with your name and email:
git config --global user.name "[[YOURNAME="yourname"]]"
git config --global user.email "[[EMAIL="email"]]"
- Now we should be able to clone the repository:
git clone https://github.com/NatNextWork1/nextwork-flask-backend.git
What am I cloning?
You are cloning the nextwork-flask-backend repository from GitHub. This repository contains all the backend code needed for your application, including files like app.py, Dockerfile, and requirements.txt.
By cloning this repository, you're copying all the code and resources onto your EC2 instance so you can build, run, and deploy the backend part of your project.
Once you've cloned it, the project will look like a new folder in your EC2 instance with the entire project's files inside.
- Run ls, which is the Linux command to list all files and subdirectories in your current directory.
- Confirm that you have a new folder called nextwork-flask-backend in your EC2 instance now.
Why does the repository name say 'flask'?
The repository is named with flask because the backend code is built using Flask, a web framework for Python that developers use to create backend services or APIs quickly. It's called a "framework" because Flask comes with templates for building web applications, making it easier to create features like handling HTTP requests managing databases.
Tip: You'll explore the backend code in depth in this project's Secret Mission 💎
Nice work, seeing the folder means you've successfully cloned your team member's backend code!
Build a Container Image for Your Backend
Great, we've got our team member's code sitting in our EC2 instance.
On to deployment?! 👀
Oooo not so fast. When you deploy a containerized app to Kubernetes, Kubernetes needs to pull the app from a container image that it can access.
What is a container image?
A container image bundles your app’s code, libraries, and settings into a single file. Kubernetes pulls that image to start identical containers, which are live copies of your app.
Because every container comes from the same image, the app will behave the same on your laptop, in testing, and in production. When you need more capacity (e.g. when there's a lot of traffic going to your app), Kubernetes can simply launch more containers from the image, keeping behavior consistent and scaling smooth.
In this step, get ready to:
- Build a container image of the backend.
- Resolve four installation and configuration errors 🤯 You're a PRO so you've absolutely got this - you could even challenge yourself to solve some of them without the guide!
- To build a container image, run the following command in your EC2 instance's terminal:
docker build -t nextwork-flask-backend .
What does building an image mean?
When your team member prepared the app's backend, they wrote a file called a Dockerfile and stored it inside their GitHub repository.
A Dockerfile contains instructions on how to build a container image that packages up an app (in this case, the backend) and all its dependencies. When you run docker build, Docker follows the Dockerfile to to build a container image.
A container image lets Docker set up multiple, identical containers so your application runs consistently across different environments. Whether you're deploying in development, testing, or production, your app behaves the same way because Docker refers to the same image each time.
💡 What do these commands do?
-t nextwork-flask-backend names your container image nextwork-flask-backend, and the . tells Docker to find the Dockerfile in the current directory.
- Yikes! An error...
What is this error about?
Remember what a "command not found" error usually tells you?
Docker isn't installed in your EC2 instance yet!
Install and Configure Docker
- Install Docker:
sudo yum install -y docker
What is Docker?
Docker is the tool we're using to build a container image of our backend. In general, you'd use Docker to create containers and container images, while Kubernetes coordinate multiple containers (clusters) running the same/related applications.
If you're new to Docker or container images, check out our intro project to Docker!
- Start Docker:
sudo service docker start
Build the Docker Image
- Run the command to build your container image again:
docker build -t nextwork-flask-backend .
What! What's the error this time?
The commands you ran to install Docker installed it for the root account, so only your root user can talk to the Docker engine. BUT, you've actually set up this Instance Connect session with another user called ec2-user, so Docker commands are blocked.
The Docker commands you ran before this worked because they're prefixed with sudo, which lets a non-root user run commands with root user rights. But, it's good practice to give your ec2-user the permission instead of using sudo each time.
💡 Why am I logged in as ec2-user instead of the root user?
When you launch an EC2 instance using certain AMIs like Amazon Linux, the default user for SSH access is ec2-user. This user comes pre-set up with the AMI as a normal user that's allowed to have root user privileges if you run a command with sudo.
When you access your instance as ec2-user, it’s like logging into an AWS account as an IAM admin user - you’ve got a lot of control but not the absolute top level (the top level user is the root user). If you need to run Docker commands, Docker needs root-level access to create containers or build container images.
- To confirm which user you're using in the terminal, run the command whoami
- You should see ec2-user in the terminal response.
- Add ec2-user to the Docker group:
sudo usermod -a -G docker ec2-user
What is the Docker group?
The Docker group is a group in Linux systems that gives users the permission to run Docker commands. By default, only the root user can run Docker commands. When you add a user (e.g., ec2-user) to the Docker group, it lets that user run Docker commands without typing sudo every time.
💡 What does this command do?
The command sudo usermod -a -G docker ec2-user adds the ec2-user to the docker group.
- usermod is used to modify a user's account in the system. It allows you to update attributes like their groups, home directory, login name, and more.
- The -a flag (append) makes sure your user doesn't get removed from any other groups they might already belong to. Without -a, the user would be removed from all groups not listed in the command.
- The -G flag (group) specifies the groups a user should be added to. In this case, it's the docker group.
- Restart your EC2 Instance Connect session by refreshing your current tab.
Why are we refreshing our tab?
User group changes don’t take effect until you start a new session! Reconnect to your EC2 instance so ec2-user picks up the new docker group permissions.
- Make sure your ec2-user has been added to the Docker group:
groups ec2-user
What does this command do?
This command will list all the groups that ec2-user is a part of.
If you see docker listed, then ec2-user is in the Docker group. Nice work - you can run Docker commands without using sudo!
- Can you run the command to build your Docker image now? You can press the up arrows (⬆) in your keyboard until you get the command pre-filled in your terminal.
Ooof, another error!
Yup! Your command won't work because your terminal needs a Dockerfile to build a container image, but it can't seem to find one right now...
- Run ls to find your subdirectories.
What are the results telling me?
Your terminal is showing us the subdirectories (i.e. the folders) sitting at the root level of your EC2 instance. One of them is nextwork-flask-backend - the code you cloned from GitHub. That folder contains everything for the backend, including the Dockerfile.
To build the Docker image, we actually need to navigate our terminal into the nextwork-flask-backend subdirectory. Otherwise, Docker can't find a Dockerfile to build your container image.
- Navigate to the application directory, which contains the Dockerfile:
cd nextwork-flask-backend
- Run ls to see the contents inside nextwork-flask-backend.
- Nice - the terminal should show you all the files inside nextwork-flask-backend, which should include the Dockerfile.
- Run the command to build your Docker image again:
docker build -t nextwork-flask-backend .
- Phew! The command works now. Watch your terminal update as Docker builds the container image.
Push Your Container Image to Amazon ECR
Now that we've built your container image, where should Kubernetes find it?
Container registries, like Amazon Elastic Container Registry (ECR), are storage spaces for container images. They give container images somewhere to live so they can be accessed by Kubernetes/other services.
Recap: Why are we using Docker and ECR?
First, we’re using Docker to wrap your backend code, its libraries, and settings into a single “container image” so the app runs the same everywhere.
Then, Amazon ECR (Elastic Container Registry) is a secure cloud repository that stores those images. You push the image once, and when Kubernetes goes to launch your app it simply pulls the image from ECR.
This workflow gives engineering teams consistency across different members, wiping out the “it works on my machine” problem. It also lets Kubernetes respond quickly if traffic to your app ever spikes - it can spin up extra identical containers running your app in seconds.
In this step, get ready to:
- Store the Docker image of your backend in ECR.
- Create a new Amazon ECR repository using this command:
aws ecr create-repository \
--repository-name nextwork-flask-backend \
--image-scanning-configuration scanOnPush=true \
Why are we using ECR?
Amazon ECR (Elastic Container Registry) is a container registry service by AWS, which means you use it to securely store, share, and deploy container images.
ECR is an excellent choice for storing your container image! It's an AWS service, which lets Elastic Kubernetes Service (EKS) deploy your container image with minimal authentication setup.
Tip: If you're new to container registries, check out our project on using Amazon ECR.
💡 Extra for Experts: Does Kubernetes only use container images from a repository?
Kubernetes can start a container from any image it has access to - not just images in a repository.
The usual way is to pull the image from a registry like ECR or Docker Hub, because that keeps deployment simple: every instance in your Kubernetes cluster would use the same, up-to-date image on demand.
You could skip the registry and copy the image onto each instace by hand, but then you’d have to repeat that step every time the image changes (yikes, that's definitely a slower process). Using a registry frees you from that manual work, and keeps your cluster up to date automatically.
- After a few seconds, your terminal should finish running your command and output this:
Woah! What does the terminal's response mean?
This response confirms that your ECR repository is created - it's ready for you to push Docker images.
💡 Extra for Experts: Here's a breakdown of the terminal response!
- repositoryArn: The Amazon Resource Name (ARN) i.e. unique ID for your ECR repository.
- repositoryUri: This is the URL you'll use to push and pull container images. It shows where your images will be stored.
- repositoryName: The name you've given to your repository - in this case, nextwork-flask-backend.
- repositoryName: The name you've given to your repository - in this case, nextwork-flask-backend.
- imageTagMutability: Whether image tags are mutable or immutable. "MUTABLE" means you can overwrite which image has a tag e.g. the latest tag can be taken by a newer image at any time.
- imageScanningConfiguration: Whether images will be scanned for vulnerabilities when pushed.
- encryptionConfiguration: Your images are encrypted using AES256 for security.
- In a new tab, head to the ECR console.
- Confirm that you can see a new repository called nextwork-flask-backend!
Nice, our Amazon ECR repository is live. We're ready to push our container image into ECR!
Push your container image to ECR
- Select your new repository.
- Select View push commands.
What is a push command?
Push commands are terminal commands you run to tell Docker to take the container image sitting in your EC2 instance and “push” it into your ECR repository.
- Copy the first command.
- Run the command in your EC2 Instance Connect window.
What's that warning about? Is this an error?
No, that's not an error! It's just a warning from Docker about how it stores your login credentials.
Docker keeps your ECR login info on your local machine, so you don’t need to authenticate to ECR every time you run an ECR command. It’s super convenient, but not the most secure approach. For better security, your credentials should live somewhere safer, like a dedicated credentials manager.
P.S. If you want to try out AWS’s credentials manager for yourself, check out our project: Secure Secrets with Secrets Manager
- Head back to your ECR console's push commands window.
- We've already built our container image, so we can skip the second command.
- Copy the last two push commands.
- Run the last two in your EC2 Instance Connect terminal to tag and push your container image.
What do tagging and pushing the image do?
Since your ECR repository can hold many versions of the same container image, tags help you keep things organized. Tagging your Docker image is like giving it a nickname so you can easily refer to a specific version.
Here, we're tagging our Docker image with latest so Kubernetes knows where it can find the right container image version when it’s time to deploy.
Pushing uploads the tagged image to a remote repository. In our case, we've just uploaded our container image to our ECR repository!
- Head back to the ECR console.
- Close the push commands window.
- Select the refresh button to refresh your console.
- Wooo! Confirm that a new container image is in your console now.
Secret mission
Welcome to your 🤫 exclusive 🤫 secret mission.
Your mission, should you choose to accept it, is to explore the backend repository you cloned. By the end of this mission, you’ll truly know what was inside the Docker image you built and pushed in this project.
💎 In this secret mission, get ready to:
- Open the backend repository on GitHub.
- Explore the three files that make up the backend.
- Showcase your secret mission in your project documentation.
Dive into the Backend Code
Delete Your Resources
Delete Your Resources
Did you know Project Three of this series will pick up right where we left off?
You can keep your resources if you're also doing Project Three today. Don't forget - EKS charges your AWS account by the hour, so delete the resources in your AWS account if you're planning to continue this series another day.
Before diving into the steps for deleting your resources, why not challenge yourself to delete everything in this project on your own?
Keeping track of your resources and deleting them without any guidance is absolutely a skill that will help you protect you from unexpected charges!!
Yep, all done.
- EKS cluster
- EC2 instance
- ECR Repository
I know, but also, I don't...
If you're feeling stuck (we've all been there!), here's a little guide:
- Delete EKS Cluster
- Delete your EKS cluster using EC2 Instance Connect:
eksctl delete cluster --name nextwork-eks-cluster
This command deletes the EKS cluster and all associated resources! It takes a bit of time before everything's gone, but you can move on to deleting other resources while you wait.
- Terminate EC2 Instance
- Head to the EC2 console.
- Select the checkbox next to nextwork-eks-instance.
- Select Instance state -> Terminate (delete) instance.
- Delete ECR Repository
- Head in the AWS console.
- Select the nextwork-flask-backend repository.
- Click Delete and confirm.
Please check - is your EKS cluster removed? Is everything in the CloudFormation stack deleted?
Please also check for an Elastic IP address in the EC2 console - some students have been charged by the Elastic IP still being in their account!
That's a wrap!
That's a wrap!
You've just learnt how to set up your app for deployment with Kubernetes 🤯
That's awesome! Give yourself a pat on the back.
You've learned how to:
- 👩💻 Use Git to pull application code.
- 🐳 Build a Docker image.
- 💿 Push Docker image to ECR.
- 🕵️ Troubleshoot installation and configuration issues.
Are you ready to quiz yourself? 💪
In the next project of this Kubernetes series, you'll get to know the key ingredient in Kubernetes deployments - manifest files!
Lots of learnings are in store see you in the next project: Create Kubernetes Manifests
p.s. Does it say "Still tasks to complete!" at the bottom of the screen?
This means you still have screenshots left to upload, or questions left to answer!
- Press Ctrl+F (Windows) or Command+F (Mac) on your keyboard.
- Search for the text Return to later.
- Jump straight to your incomplete tasks!
- 🙋♀️ Still stuck? Ask the community!