All checks were successful
Build and Deploy Hugo / Deploy Hugo Website (pull_request) Successful in 24s
Remove emojis and em dash separators Simplify introductory sentences Standardize section headings
318 lines
12 KiB
Markdown
318 lines
12 KiB
Markdown
---
|
||
title: "DevPod on AWS"
|
||
date: 2025-02-11T20:00:00+02:00
|
||
weight: 1
|
||
cascade:
|
||
type: docs
|
||
---
|
||
|
||
## Sources
|
||
|
||
- [DevPod](https://devpod.sh/docs/what-is-devpod) ⚙️
|
||
- [DevContainer](https://containers.dev) 🐳
|
||
|
||
## Introduction
|
||
|
||
In this article, I want to introduce a fantastic tool that belongs to the same family as GitPod and Codespaces: **DevPod**! It lets you create development environments effortlessly — without getting locked in to a single provider. 🔒❌
|
||
|
||
DevPod is based on the **DevContainer** architecture and uses the specifications contained in a [devcontainer.json](https://containers.dev) file to launch your development environment. Personally, I use it to quickly deploy network mockups with ContainerLab. 💻🧰
|
||
|
||
## What is a DevContainer?
|
||
|
||
A development container (often called a "dev container") lets you use a container as a full-fledged development environment. (Check out the official [containers.dev](https://containers.dev) documentation for more details.)
|
||
|
||
Let's break it down:
|
||
|
||
Have you ever heard the phrase "It works on my machine"? If you're a developer, you've probably run into this problem when collaborating with others. But guess what? **DevContainers** solve the problem of environment drift by providing consistent, reproducible Docker environments. Say goodbye to installation headaches! 💆♀️
|
||
|
||
With DevContainers, all you need is:
|
||
|
||
1. A `.devcontainer` folder in your project.
|
||
2. A `devcontainer.json` file that tells VS Code how to configure the container.
|
||
3. Docker installed locally
|
||
|
||
The cornerstone of the DevContainer is the `devcontainer.json` file. For example:
|
||
|
||
```json
|
||
{
|
||
"name": "Python DevContainer",
|
||
"image": "mcr.microsoft.com/devcontainers/python:3.10",
|
||
"features": {
|
||
"docker-in-docker": "latest"
|
||
},
|
||
"extensions": [
|
||
"ms-python.python",
|
||
"ms-azuretools.vscode-docker"
|
||
]
|
||
}
|
||
```
|
||
|
||
**What's happening here?** 🕵️♀️
|
||
|
||
- **"image"** – This uses a ready-to-use Python 3.10 environment.
|
||
- **"features"** – This adds Docker support inside the container.
|
||
- **"extensions"** – Installs useful extensions for Python and Docker in VS Code.
|
||
|
||
DevContainers are great for local development, but sometimes you need more power — maybe your workloads are huge, or you want to run specialized labs. That's where **DevPod** comes in. 💪
|
||
**So you can easily deploy labs to the Cloud**
|
||
|
||
## What is DevPod?
|
||
|
||
**DevPod** is an open-source tool that lets you launch development environments either on your local machine or in the cloud provider of your choice. Think of it as a self-hosted, highly customizable version of GitHub Codespaces. 🎉
|
||
|
||
In my day-to-day networking adventures, I deploy ContainerLab-based setups with DevContainers on AWS. Let's see how you can use DevPod to do exactly that (details on ContainerLab will follow in another article, I promise!). 😜
|
||
|
||
## AWS provider
|
||
|
||
DevPod uses **Providers**, which are configuration modules that define where and how DevPod launches your environment. Here's the list of providers:
|
||
|
||

|
||
|
||
We're going to focus on the **AWS Provider** — even though there are plenty of configuration options:
|
||
|
||

|
||
|
||
Before you panic at all these settings, don't worry. If you're just doing a bit of experimenting, the default values will usually do the job. 🙌
|
||
|
||
> [!NOTE] **The perks of open source**
|
||
>
|
||
> The fact that DevPod is open-source means you can peek under the hood to see exactly how it works. Check out the AWS code [here](https://github.com/loft-sh/devpod-provider-aws/tree/main) if you're curious.
|
||
|
||
## How the AWS code works
|
||
|
||
Let's look at what DevPod does on AWS by examining the [aws.go code](https://github.com/loft-sh/devpod-provider-aws/blob/main/pkg/aws/aws.go). At a high level, it handles:
|
||
|
||
1. **Initialization**: Reading the configuration and setting up the AWS SDK clients (with custom credentials if needed).
|
||
2. **Networking**: Finding or creating the appropriate subnet, VPC, and security groups.
|
||
3. **AMI selection**: Choosing a suitable AMI (by default, a recent Ubuntu 22.04 image) and determining the root device.
|
||
4. **IAM setup**: Verifying that an appropriate instance role and instance profile exist, along with the associated policies.
|
||
5. **Instance lifecycle**: Creating, starting, stopping, checking the status of, and deleting instances.
|
||
6. **User data injection**: Generating a script (Base64-encoded) that configures the instance (adds users and SSH keys) on first boot.
|
||
7. **Optional DNS**: Managing Route 53 records for the instance if the configuration requires it.
|
||
|
||
From my perspective, two points stand out as potentially the most critical:
|
||
|
||
- **(#4) IAM setup**
|
||
- **(#6) User data injection**
|
||
|
||
### Why are points #4 and #6 "tricky"?
|
||
|
||
- **IAM setup** is mainly handled by the `CreateDevpodInstanceProfile` function. It creates a role named `devpod-ec2-role` that can perform the following operations:
|
||
- **EC2 operations**: For example, it can describe or stop instances — in particular, the instance associated with it.
|
||
- **SSM operations**: By attaching the AmazonSSMManagedInstanceCore policy, the instance can be managed by AWS Systems Manager.
|
||
- **KMS operations (optional)**: If configured, it can run `kms:Decrypt` on a specific KMS key, which is useful for managing session data or secrets.
|
||
|
||
- **User data injection** is essentially a startup script inserted into the instance as Base64. This script sets up a `devpod` user with sudo rights, creates the SSH folders, and inserts your public key into the appropriate file. In the code, [it looks like this](https://github.com/loft-sh/devpod-provider-aws/blob/9d2730c34ecee40cb42596c602381b92ad9c6682/pkg/aws/aws.go#L967-L980):
|
||
|
||
```bash
|
||
useradd devpod -d /home/devpod
|
||
mkdir -p /home/devpod
|
||
if grep -q sudo /etc/groups; then
|
||
usermod -aG sudo devpod
|
||
elif grep -q wheel /etc/groups; then
|
||
usermod -aG wheel devpod
|
||
fi
|
||
|
||
echo "devpod ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/91-devpod
|
||
mkdir -p /home/devpod/.ssh
|
||
echo " + string(publicKey) + " >> /home/devpod/.ssh/authorized_keys
|
||
chmod 0700 /home/devpod/.ssh
|
||
chmod 0600 /home/devpod/.ssh/authorized_keys
|
||
chown -R devpod:devpod /home/devpod
|
||
```
|
||
|
||
Since DevPod is open-source, you can easily check it out for yourself. It's a great learning tool if you want to understand all the inner workings! 🔩
|
||
|
||
## IAM roles and policies
|
||
|
||
You'll need to create an IAM user and attach an IAM policy to it that grants just enough permissions for DevPod. For example:
|
||
|
||
- **EC2 actions:**
|
||
- Description: `ec2:DescribeSubnets`, `ec2:DescribeVpcs`, `ec2:DescribeImages`, `ec2:DescribeInstances`, `ec2:DescribeSecurityGroups`
|
||
- Instance management: `ec2:RunInstances`, `ec2:StartInstances`, `ec2:StopInstances`, `ec2:TerminateInstances`, `ec2:CancelSpotInstanceRequests`
|
||
- Security groups & tags: `ec2:CreateSecurityGroup`, `ec2:AuthorizeSecurityGroupIngress`, `ec2:CreateTags`
|
||
- **IAM actions:**
|
||
- `iam:GetInstanceProfile`, `iam:CreateRole`, `iam:PutRolePolicy`, `iam:AttachRolePolicy`, `iam:CreateInstanceProfile`, `iam:AddRoleToInstanceProfile`
|
||
- **Route 53 (optional):**
|
||
- `route53:ListHostedZones`, `route53:GetHostedZone`, `route53:ChangeResourceRecordSets`
|
||
|
||
## AWS configuration
|
||
|
||
I usually use the AWS web console to set this up, but you can absolutely do it via the CLI too.
|
||
|
||
### Step 1: Log in to the AWS console
|
||
|
||
1. Go to the [AWS Management Console](https://aws.amazon.com/console/).
|
||
2. Use an account with the appropriate rights to create IAM resources.
|
||
|
||
### Step 2: Create a custom IAM policy
|
||
|
||
#### **A. Go to the IAM console**
|
||
|
||
- In the AWS menu, find **IAM**.
|
||
|
||
#### **B. Create a new policy**
|
||
|
||
1. Click **Policies** in the left-hand menu.
|
||
2. Click **Create policy**.
|
||
|
||
#### **C. Switch to the JSON tab**
|
||
|
||
- Paste something like this, adjusting as needed:
|
||
|
||
```json
|
||
{
|
||
"Version": "2012-10-17",
|
||
"Statement": [
|
||
{
|
||
"Sid": "EC2Actions",
|
||
"Effect": "Allow",
|
||
"Action": [
|
||
"ec2:DescribeSubnets",
|
||
"ec2:DescribeVpcs",
|
||
"ec2:DescribeImages",
|
||
"ec2:DescribeInstances",
|
||
"ec2:DescribeSecurityGroups",
|
||
"ec2:RunInstances",
|
||
"ec2:StartInstances",
|
||
"ec2:StopInstances",
|
||
"ec2:TerminateInstances",
|
||
"ec2:CancelSpotInstanceRequests",
|
||
"ec2:CreateSecurityGroup",
|
||
"ec2:AuthorizeSecurityGroupIngress",
|
||
"ec2:CreateTags",
|
||
"ec2:DeleteTags"
|
||
],
|
||
"Resource": "*"
|
||
},
|
||
{
|
||
"Sid": "IAMActions",
|
||
"Effect": "Allow",
|
||
"Action": [
|
||
"iam:GetInstanceProfile",
|
||
"iam:CreateRole",
|
||
"iam:PutRolePolicy",
|
||
"iam:AttachRolePolicy",
|
||
"iam:CreateInstanceProfile",
|
||
"iam:AddRoleToInstanceProfile"
|
||
],
|
||
"Resource": "*"
|
||
},
|
||
{
|
||
"Sid": "Route53Actions",
|
||
"Effect": "Allow",
|
||
"Action": [
|
||
"route53:ListHostedZones",
|
||
"route53:GetHostedZone",
|
||
"route53:ChangeResourceRecordSets"
|
||
],
|
||
"Resource": "*"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
- Click **Next** (tags are optional), then **Next: Review**.
|
||
|
||
#### **D. Review and create**
|
||
|
||
1. Name it `DevpodToolPolicy` (or whatever you prefer).
|
||
2. Add an optional description.
|
||
3. Click **Create policy**.
|
||
|
||
### Step 3: Create or update the IAM user
|
||
|
||
#### **A. Create a new user (if needed)**
|
||
|
||
1. Click **Users** in IAM.
|
||
2. Click **Add user**.
|
||
3. Give it a name (e.g., `devpod-tool-user`).
|
||
4. Choose **Programmatic access** if you want CLI access. 🤖
|
||
5. Click **Next**.
|
||
|
||
#### **B. Attach your new policy**
|
||
|
||
1. On the permissions page, choose **Attach policies directly**.
|
||
2. Check `DevpodToolPolicy`.
|
||
3. Click **Create**.
|
||
4. And there you go!
|
||
|
||
### Step 4: Verify and you're done
|
||
|
||
Go back to **Users** → **devpod-tool-user** → **Permissions** to confirm that `DevpodToolPolicy` is indeed attached. ✅
|
||
|
||
### Step 5: Use these credentials
|
||
|
||
- If you created a programmatic user, make sure to note down the **Access Key ID** and the **Secret Access Key**.
|
||
|
||

|
||
|
||
**Bonus**: Note your **VPC ID** (in the VPC section on AWS). You'll need it when configuring DevPod.
|
||
|
||
## Configuring DevPod
|
||
|
||
### 1. Configure the AWS profile
|
||
|
||
```bash
|
||
aws configure --profile Devpod
|
||
```
|
||
|
||
When prompted for:
|
||
|
||
1. The Access Key ID
|
||
2. The Secret Access Key
|
||
3. The default region (e.g., `eu-west-1`)
|
||
4. The output format (I usually leave it blank)
|
||
|
||
### 2. Add the profile to DevPod
|
||
|
||
1. In DevPod, create a new provider and choose **AWS**.
|
||
2. Select the **AWS region** (e.g., `eu-west-1`).
|
||
3. Expand the AWS options.
|
||
4. **AWS disk size**: e.g., 40 GB to start.
|
||
5. **Instance type**: e.g., `t2.small`.
|
||
6. **AWS profile**: select `Devpod` (or whatever name you chose).
|
||
7. **AWS VPC ID**: add your VPC.
|
||
8. You can leave the rest as default.
|
||
|
||
Click **Add Provider**.
|
||
|
||

|
||
|
||
## Testing a deployment
|
||
|
||
### Deploy
|
||
|
||
Let's do a quick test using one of the pre-built Docker images:
|
||
|
||
1. Go to **Workspaces** in DevPod.
|
||
2. Click **Create Workspace**.
|
||
3. Choose your new **AWS** provider.
|
||
4. Choose your preferred IDE (VS Code, etc.).
|
||
5. On the right, select a quick-start example (e.g., Python). 🐍
|
||
6. Click **Create Workspace**.
|
||
|
||

|
||
|
||
Wait a few moments, and your cloud-based environment will pop up in VS Code. 🎊
|
||
|
||

|
||
|
||
### Stop
|
||
|
||
When you're not using the environment, click **Stop** to shut down the EC2 instance. You'll only pay for storage — no compute time. Great for your wallet. 💰
|
||
|
||

|
||
|
||
### Delete
|
||
|
||
Deleting the workspace removes all AWS resources associated with that environment, so you won't pay a dime. But you'll need to redeploy if you want to use it again. ♻️
|
||
|
||

|
||
|
||
## Conclusion
|
||
|
||
By combining **DevContainers** and **DevPod** on **AWS**, you can build flexible, self-managed development environments that scale with your needs, without being locked into vendor-specific platforms. Say goodbye to "It works on my machine!" issues and hello to frictionless coding.
|
||
|
||
Have fun!
|