This guide was recovered from the Wayback Machine snapshot of “Deploy an application with CDK for Terraform”.
- Create a local Kubernetes cluster with kind.
- Convert an existing Terraform configuration into TypeScript.
- Refactor into reusable constructs and add tests.
- Deploy custom frontend and backend images via a local registry.
- Deploy a second stack representing a test environment.
Prerequisites
- Terraform v1.2+ (or OpenTofu)
- CDKTN v0.15+
- Docker Desktop (or equivalent) installed and running
- Node.js (v18+) and npm (v8.19+)
kubectlkind
CDKTN works with both Terraform and OpenTofu. To run OpenTofu, set
TERRAFORM_BINARY_NAME=tofu before using the CLI. Refer to Environment Variables for details.Clone example repository
Shell
Copy
Ask AI
git clone https://github.com/hashicorp-education/learn-terraform-cdktf-applications
Shell
Copy
Ask AI
cd learn-terraform-cdktf-applications
Start a local registry
Start a local Docker registry on127.0.0.1:5000.
Shell
Copy
Ask AI
docker run -d --restart always -p "127.0.0.1:5000:5000" --name local-registry registry:2 Unable to find image 'registry:2' locally 2: Pulling from library/registry 530afca65e2e: Already exists d450d4da0343: Pull complete 96277bea17b6: Pull complete 470ad04e03fb: Pull complete bd3d4dc6e66f: Pull complete Digest: sha256:c631a581c6152f5a4a141a974b74cf308ab2ee660287a3c749d88e0b536c0c20 Status: Downloaded newer image for registry:2 2d9c6166d2ea3b1f6ef9d933afa6069eef5e2dbaece27ce1b235b89b7c5d374b
Create a kind cluster
Create the cluster.Shell
Copy
Ask AI
kind create cluster --name=cdktf-app --config kind-config.yaml Creating cluster "cdktf-app" ... ✓ Ensuring node image (kindest/node:v1.25.0) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-cdktf-app" You can now use your cluster with: kubectl cluster-info --context kind-cdktf-app Not sure what to do next? 😅 Check out https://kind.sigs.k8s.io/user/quick-start/
Shell
Copy
Ask AI
kind get clusters cdktf-app
Shell
Copy
Ask AI
kubectl cluster-info --context=kind-cdktf-app Kubernetes control plane is running at https://127.0.0.1:56821 CoreDNS is running at https://127.0.0.1:56821/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Shell
Copy
Ask AI
kubectl config view --raw --context kind-cdktf-app > kubeconfig.yaml
Shell
Copy
Ask AI
docker network connect kind local-registry
Shell
Copy
Ask AI
kubectl apply -f local-registry-configmap.yaml --kubeconfig kubeconfig.yaml configmap/local-registry-hosting created
Initialize your CDKTN application
Create theapp/ directory and move into it.
Shell
Copy
Ask AI
mkdir app
Shell
Copy
Ask AI
cd app
Shell
Copy
Ask AI
cdktn init --template=typescript \
--project-name=learn-terraform-cdktf-applications \
--project-description="Learn how to develop CDKTN applications" \
--providers="kubernetes@~>2.14" \
--local
Create a Kubernetes Deployment
Convert the provided Terraform configuration into TypeScript.Shell
Copy
Ask AI
cat ../k8s_deployment.tf | cdktn convert --provider=kubernetes /*Provider bindings are generated by running cdktn get. See https://cdk.tf/provider-generation for more details.*/ import * as kubernetes from "./.gen/providers/kubernetes"; new kubernetes.deployment.Deployment(this, "myapp", { metadata: { labels: { app: "myapp", component: "frontend", environment: "dev", }, name: "myapp-frontend-dev", }, spec: { replicas: "1", selector: { matchLabels: { app: "myapp", component: "frontend", environment: "dev", }, }, template: { metadata: { labels: { app: "myapp", component: "frontend", environment: "dev", }, }, spec: {
Shell
Copy
Ask AI
npm install path added 299 packages, and audited 357 packages in 3s 33 packages are looking for funding run `npm fund` for details found 0 vulnerabilities
Shell
Copy
Ask AI
cdktn synth Generated Terraform code for the stacks: app
Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Successfully configured the backend "local"! Terraform will automatically use this backend unless the backend configuration changes. app Initializing provider plugins... app - Finding hashicorp/kubernetes versions matching "2.14.0"... app - Using hashicorp/kubernetes v2.14.0 from the shared cache directory ##... Plan: 1 to add, 0 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop ##... app kubernetes_deployment.myapp (myapp): Creating... app kubernetes_deployment.myapp (myapp): Creation complete after 8s [id=default/myapp] app Apply complete! Resources: 1 added, 0 changed, 0 destroyed. No outputs found.
Shell
Copy
Ask AI
kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp 1/1 1 1 117s
Scale the deployment
After you update the deployment to use 4 replicas, deploy again.Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Initializing provider plugins... app - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 app Terraform has been successfully initialized! ##... Terraform will perform the following actions: app # kubernetes_deployment.myapp (myapp) will be updated in-place ~ resource "kubernetes_deployment" "myapp" { id = "default/myapp" # (1 unchanged attribute hidden) ~ spec { ~ replicas = "1" -> "4" # (4 unchanged attributes hidden) # (3 unchanged blocks hidden) } # (1 unchanged block hidden) } Plan: 0 to add, 1 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan.
Shell
Copy
Ask AI
kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp 4/4 4 4 8m31s
Refactor your deployment
Create aconstructs/ directory.
Shell
Copy
Ask AI
mkdir constructs
constructs/kubernetes-web-app.ts.
TypeScript
Copy
Ask AI
import { Construct } from "constructs"
import * as kubernetes from "@cdktn/provider-kubernetes"
export interface KubernetesWebAppDeploymentConfig {
readonly image: string
readonly replicas: number
readonly app: string
readonly component: string
readonly environment: string
readonly env?: Record<string, string>
}
export class KubernetesWebAppDeployment extends Construct {
public readonly resource: kubernetes.deployment.Deployment
constructor(
scope: Construct,
name: string,
config: KubernetesWebAppDeploymentConfig
) {
super(scope, name)
this.resource = new kubernetes.deployment.Deployment(this, name, {
metadata: {
labels: {
app: config.app,
component: config.component,
environment: config.environment,
},
name: `${config.app}-${config.component}-${config.environment}`,
},
spec: {
replicas: config.replicas.toString(),
selector: {
matchLabels: {
app: config.app,
component: config.component,
environment: config.environment,
},
},
template: {
metadata: {
labels: {
app: config.app,
component: config.component,
environment: config.environment,
},
},
spec: {
container: [
{
image: config.image,
name: `${config.app}-${config.component}-${config.environment}`,
env: Object.entries(config.env || {}).map(([name, value]) => ({
name,
value,
})),
},
],
},
},
},
})
}
}
constructs/index.ts.
TypeScript
Copy
Ask AI
export * from "./kubernetes-web-app"
app/main.ts to use your new construct.
TypeScript
Copy
Ask AI
import { Construct } from "constructs"
import { App, TerraformStack } from "cdktn"
import * as kubernetes from "@cdktn/provider-kubernetes"
import * as path from "path"
import { KubernetesWebAppDeployment } from "./constructs"
class MyStack extends TerraformStack {
constructor(scope: Construct, name: string) {
super(scope, name)
new kubernetes.provider.KubernetesProvider(this, 'kind', {
configPath: path.join(__dirname, '../kubeconfig.yaml'),
})
new KubernetesWebAppDeployment(this, 'deployment', {
image: 'nginx:latest',
replicas: 2,
app: 'myapp',
component: 'frontend',
environment: 'dev',
})
}
}
const app = new App()
new MyStack(app, 'app')
app.synth()
Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Initializing provider plugins... app - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 app Terraform has been successfully initialized! ##... Plan: 1 to add, 0 to change, 1 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop ##... app kubernetes_deployment.myapp: Destroying... [id=default/myapp] app kubernetes_deployment.deployment_7B0B4E40 (deployment/deployment): Creating... app kubernetes_deployment.myapp: Destruction complete after 0s app kubernetes_deployment.deployment_7B0B4E40 (deployment/deployment): Creation complete after 8s [id=default/myapp-frontend-dev] app Apply complete! Resources: 1 added, 0 changed, 1 destroyed. No outputs found.
Shell
Copy
Ask AI
kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp-frontend-dev 2/2 2 2 5m14s
Add tests
Createapp/jest.setup.js.
JavaScript
Copy
Ask AI
const cdktn = require('cdktn')
cdktn.Testing.setupJest()
app/__tests__/kubernetes-web-app-test.ts.
TypeScript
Copy
Ask AI
import "cdktn/lib/testing/adapters/jest"
import { Testing } from "cdktn"
import * as kubernetes from "@cdktn/provider-kubernetes"
import { KubernetesWebAppDeployment } from "../constructs"
describe('Our CDKTN Constructs', () => {
describe('KubernetesWebAppDeployment', () => {
it('should contain a deployment resource', () => {
expect(
Testing.synthScope((scope) => {
new KubernetesWebAppDeployment(scope, 'myapp-frontend-dev', {
image: 'nginx:latest',
replicas: 4,
app: 'myapp',
component: 'frontend',
environment: 'dev',
})
})
).toHaveResource(kubernetes.deployment.Deployment)
})
})
})
Shell
Copy
Ask AI
npm run test > app@1.0.0 test > jest PASS __tests__/main-test.ts PASS __tests__/kubernetes-web-app-test.ts Test Suites: 2 passed, 2 total Tests: 1 todo, 1 passed, 2 total Snapshots: 0 total Time: 5.109 s Ran all test suites.
Add a NodePort Service
Add a NodePort service interface.TypeScript
Copy
Ask AI
export interface KubernetesNodePortServiceConfig {
readonly port: number
readonly app: string
readonly component: string
readonly environment: string
}
TypeScript
Copy
Ask AI
export class KubernetesNodePortService extends Construct {
public readonly resource: kubernetes.service.Service
constructor(
scope: Construct,
name: string,
config: KubernetesNodePortServiceConfig
) {
super(scope, name)
this.resource = new kubernetes.service.Service(this, name, {
metadata: {
name: `${config.app}-${config.component}-${config.environment}`,
},
spec: {
type: 'NodePort',
port: [
{
port: 80,
targetPort: '80',
nodePort: config.port,
protocol: 'TCP',
},
],
selector: {
app: config.app,
component: config.component,
environment: config.environment,
},
},
})
}
}
TypeScript
Copy
Ask AI
describe('KubernetesNodePortService', () => {
it('should contain a Service resource', () => {
expect(
Testing.synthScope((scope) => {
new KubernetesNodePortService(scope, 'myapp-frontend-dev', {
app: 'myapp',
component: 'frontend',
environment: 'dev',
port: 30001,
})
})
).toHaveResource(kubernetes.service.Service)
})
})
Shell
Copy
Ask AI
npm run test > app@1.0.0 test > jest PASS __tests__/main-test.ts PASS __tests__/kubernetes-web-app-test.ts Test Suites: 2 passed, 2 total Tests: 1 todo, 2 passed, 3 total Snapshots: 0 total Time: 5.094 s Ran all test suites.
Add a NodePortService to your application
Add the NodePort service inmain.ts.
TypeScript
Copy
Ask AI
new KubernetesNodePortService(this, 'service', {
port: 30001,
app: 'myapp',
component: 'frontend',
environment: 'dev',
})
Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Initializing provider plugins... app - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 app Terraform has been successfully initialized! ##... Plan: 1 to add, 0 to change, 0 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop ##... app kubernetes_service.service_E7C408F2 (service/service): Creating... app kubernetes_service.service_E7C408F2 (service/service): Creation complete after 0s [id=default/myapp-frontend-dev] app Apply complete! Resources: 1 added, 0 changed, 0 destroyed. No outputs found.
Shell
Copy
Ask AI
kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 101m myapp-frontend-dev NodePort 10.96.186.212 <none> 80:30001/TCP 22s
Shell
Copy
Ask AI
curl http://localhost:30001 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Refactor constructs
Destroy the stack before continuing.Shell
Copy
Ask AI
cdktn destroy app Initializing the backend... app Initializing provider plugins... app - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 app Terraform has been successfully initialized! ##... Plan: 0 to add, 0 to change, 2 to destroy. ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop app kubernetes_service.service_E7C408F2 (service/service): Destroying... [id=default/myapp-frontend-dev] app kubernetes_deployment.deployment_7B0B4E40 (deployment/deployment): Destroying... [id=default/myapp-frontend-dev] app kubernetes_deployment.deployment_7B0B4E40 (deployment/deployment): Destruction complete after 0s app kubernetes_service.service_E7C408F2 (service/service): Destruction complete after 0s app Destroy complete! Resources: 2 destroyed.
constructs/kubernetes-web-app.ts.
TypeScript
Copy
Ask AI
import { TerraformOutput } from "cdktn"
TypeScript
Copy
Ask AI
export type SimpleKubernetesWebAppConfig = KubernetesWebAppDeploymentConfig &
KubernetesNodePortServiceConfig
export class SimpleKubernetesWebApp extends Construct {
public readonly deployment: KubernetesWebAppDeployment
public readonly service: KubernetesNodePortService
public readonly config: SimpleKubernetesWebAppConfig
constructor(
scope: Construct,
name: string,
config: SimpleKubernetesWebAppConfig
) {
super(scope, name)
this.config = config
this.deployment = new KubernetesWebAppDeployment(this, 'deployment', {
image: config.image,
replicas: config.replicas,
app: config.app,
component: config.component,
environment: config.environment,
env: config.env,
})
this.service = new KubernetesNodePortService(this, 'service', {
port: config.port,
app: config.app,
component: config.component,
environment: config.environment,
})
new TerraformOutput(this, 'url', {
value: `http://localhost:${config.port}`,
})
}
}
TypeScript
Copy
Ask AI
describe('SimpleKubernetesWebApp', () => {
it('should contain a Service resource', () => {
expect(
Testing.synthScope((scope) => {
new SimpleKubernetesWebApp(scope, 'myapp-frontend-dev', {
image: 'nginx:latest',
replicas: 4,
app: 'myapp',
component: 'frontent',
environment: 'dev',
port: 30001,
})
})
).toHaveResource(kubernetes.service.Service)
})
it('should contain a Deployment resource', () => {
expect(
Testing.synthScope((scope) => {
new SimpleKubernetesWebApp(scope, 'myapp-frontend-dev', {
image: 'nginx:latest',
replicas: 4,
app: 'myapp',
component: 'frontent',
environment: 'dev',
port: 30001,
})
})
).toHaveResource(kubernetes.deployment.Deployment)
})
})
Shell
Copy
Ask AI
npm run test > app@1.0.0 test > jest PASS __tests__/main-test.ts (6.019 s) PASS __tests__/kubernetes-web-app-test.ts (8.059 s) Test Suites: 2 passed, 2 total Tests: 1 todo, 4 passed, 5 total Snapshots: 0 total Time: 8.556 s Ran all test suites.
Use the SimpleKubernetesWebApp construct
Update your imports.TypeScript
Copy
Ask AI
import { SimpleKubernetesWebApp } from "./constructs"
TypeScript
Copy
Ask AI
new SimpleKubernetesWebApp(this, 'app_frontend', {
image: 'nginx:latest',
replicas: 3,
port: 30001,
app: 'myapp',
component: 'frontend',
environment: 'dev',
})
Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Initializing provider plugins... app - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 app Terraform has been successfully initialized! ##... Plan: 2 to add, 0 to change, 0 to destroy. Changes to Outputs: + app_frontend_url_5DD99814 = "http://localhost:30001" ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop app kubernetes_service.app_frontend_service_C2863249 (app_frontend/service/service): Creating... app kubernetes_deployment.app_frontend_deployment_0EE98C72 (app_frontend/deployment/deployment): Creating... app kubernetes_service.app_frontend_service_C2863249 (app_frontend/service/service): Creation complete after 0s [id=default/myapp-frontend-dev] app kubernetes_deployment.app_frontend_deployment_0EE98C72 (app_frontend/deployment/deployment): Creation complete after 4s [id=default/myapp-frontend-dev] app Apply complete! Resources: 2 added, 0 changed, 0 destroyed. app Outputs: app_frontend_url_5DD99814 = "http://localhost:30001"
Shell
Copy
Ask AI
kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 142m myapp-frontend-dev NodePort 10.96.216.88 <none> 80:30001/TCP 44s
Shell
Copy
Ask AI
curl http://localhost:30001 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
Deploy a custom image
Build and push the frontend image.Shell
Copy
Ask AI
cd ../frontend
Shell
Copy
Ask AI
docker build . -t nocorp-frontend [+] Building 33.0s (12/12) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 295B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 67B 0.0s => [internal] load metadata for docker.io/library/node:14 1.3s => [1/7] FROM docker.io/library/node:14@sha256:109b118e0d49dd12ca6f5b84a7a9a9c8a147f75567b3ad50620bdacaf5e6320d 26.2s ## ... => [internal] load build context 0.0s => => transferring context: 718.44kB 0.0s => [2/7] WORKDIR /usr/share/app 0.2s => [3/7] COPY package*.json ./ 0.0s => [4/7] COPY frontend.js ./ 0.0s => [5/7] COPY public/ ./public/ 0.0s => [6/7] COPY views/ ./views/ 0.0s => [7/7] RUN npm install 4.8s => exporting to image 0.2s => => exporting layers 0.2s => => writing image sha256:9dc1ce3668a79770f694ddeae6a5c2236527c381cd429d850eb4a37a8c565ce1 0.0s => => naming to docker.io/library/nocorp-frontend 0.0s Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
Shell
Copy
Ask AI
docker tag nocorp-frontend:latest localhost:5000/nocorp-frontend:latest
Shell
Copy
Ask AI
docker push localhost:5000/nocorp-frontend:latest The push refers to repository [localhost:5000/nocorp-frontend] 72d21ab0ed02: Pushed a831dca05db6: Pushed 66018b4c7669: Pushed 65f4bcfe9daa: Pushed add6fa0cc975: Pushed 8628cf05347a: Pushed 85bfe2c7cf32: Pushed 28e2f0d3695c: Pushed b892edc3d92e: Pushed f1486e967e48: Pushed 5750262417ad: Pushed 9ed3c35b4335: Pushed 6f7f3f280040: Pushed d6e0d602719c: Pushed 73c3e7ef7bc6: Pushed latest: digest: sha256:f56babe32077523e891b24af0e38fe00026c7f8ed38b89d90a102aaeeb3d40b8 size: 3465
Shell
Copy
Ask AI
cd ../app
Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Initializing provider plugins... app - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 Terraform has been successfully initialized! ##... app Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: app # kubernetes_deployment.app_frontend_deployment_0EE98C72 (app_frontend/deployment/deployment) will be updated in-place ~ resource "kubernetes_deployment" "app_frontend_deployment_0EE98C72" { id = "default/myapp-frontend-dev" # (1 unchanged attribute hidden) ~ spec { # (5 unchanged attributes hidden) ~ template { ~ spec { # (11 unchanged attributes hidden) ~ container { ~ image = "nginx:latest" -> "localhost:5000/nocorp-frontend:latest" name = "myapp-frontend-dev" # (8 unchanged attributes hidden) ##... Plan: 0 to add, 1 to change, 0 to destroy. ─────────────────────────────────────────────────────────────────────────────
Shell
Copy
Ask AI
kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp-frontend-dev 3/3 3 3 43s
Shell
Copy
Ask AI
curl http://localhost:30001 <!DOCTYPE html><html><head><title>Terranimo</title></head><link rel="stylesheet" href="/styles/terramino.css"></html><body><div class="score" id="score"></div><div class="container"><div class="content"><h1>Terramino</h1><p class="error" id="errorMessage">Could not connect to server! <br/> Reload to try again.</p><p>Move: ← → Rotate: ↑ Drop: ↓</p></div><div class="content"><canvas width="320" height="640" id="game"></canvas></div></div><script src="/scripts/terramino.js"></script><script>start('http://localhost:30002')</script></body>
Add a backend service
Build and push the backend image.Shell
Copy
Ask AI
cd ../backend
Shell
Copy
Ask AI
npm run deploy > nocorp-backend-app@1.0.0 deploy /Users/<YOU>/code/learn-terraform-cdktf-applications/backend > npm run build && npm run tag && npm run push > nocorp-backend-app@1.0.0 build /Users/<YOU>/code/learn-terraform-cdktf-applications/backend > docker build . -t nocorp-backend ## ... The push refers to repository [localhost:5000/nocorp-backend] 676744aedcf3: Pushed e64b93b2c9bd: Pushed 8628cf05347a: Mounted from nocorp-frontend 85bfe2c7cf32: Mounted from nocorp-frontend 28e2f0d3695c: Mounted from nocorp-frontend b892edc3d92e: Mounted from nocorp-frontend f1486e967e48: Mounted from nocorp-frontend 5750262417ad: Mounted from nocorp-frontend 9ed3c35b4335: Mounted from nocorp-frontend 6f7f3f280040: Mounted from nocorp-frontend d6e0d602719c: Mounted from nocorp-frontend 73c3e7ef7bc6: Mounted from nocorp-frontend latest: digest: sha256:845e60dd8350066a89757f1bdb200584f317e5b15d68cc9609a3c359f3736676 size: 2841
main.ts to add a backend application.
TypeScript
Copy
Ask AI
const app_backend = new SimpleKubernetesWebApp(this, 'app_backend', {
image: 'localhost:5000/nocorp-backend:latest',
replicas: 1,
port: 30002,
app: 'myapp',
component: 'backend',
environment: 'dev',
})
Shell
Copy
Ask AI
cd ../app
Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Initializing provider plugins... - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 Terraform has been successfully initialized! ##... app Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create ~ update in-place Terraform will perform the following actions: app # kubernetes_deployment.app_backend_deployment_1A8B5520 (app_backend/deployment/deployment) will be created + resource "kubernetes_deployment" "app_backend_deployment_1A8B5520" { ##... # kubernetes_deployment.app_frontend_deployment_0EE98C72 (app_frontend/deployment/deployment) will be updated in-place ~ resource "kubernetes_deployment" "app_frontend_deployment_0EE98C72" { id = "default/myapp-frontend-dev" ##... + env { + name = "BACKEND_APP_URL" + value = "http://localhost:30002" } ##... # kubernetes_service.app_backend_service_EAD583EF (app_backend/service/service) will be created + resource "kubernetes_service" "app_backend_service_EAD583EF" { ##... Plan: 2 to add, 1 to change, 0 to destroy. Changes to Outputs: + app_backend_url_CAA2B50B = "http://localhost:30002"
Shell
Copy
Ask AI
kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp-backend-dev 1/1 1 1 57s myapp-frontend-dev 3/3 3 3 15m
Shell
Copy
Ask AI
curl http://localhost:30002/new {"game":{"id":"pdSW6Cymw","state":"running","score":0,"tetrominoSequence":["I","J","Z","O","T","S"]},"tetromino":"L"}
Deploy another application stack
Refactor the stack to accept frontend and backend configuration.TypeScript
Copy
Ask AI
class MyStack extends TerraformStack {
constructor(
scope: Construct,
name: string,
config: {
frontend: SimpleKubernetesWebAppConfig
backend: SimpleKubernetesWebAppConfig
}
) {
super(scope, name)
new kubernetes.provider.KubernetesProvider(this, 'kind', {
configPath: path.join(__dirname, '../kubeconfig.yaml'),
})
const app_backend = new SimpleKubernetesWebApp(
this,
'app_backend',
config.backend
)
new SimpleKubernetesWebApp(this, 'app_frontend', {
...config.frontend,
env: { BACKEND_APP_URL: `http://localhost:${app_backend.config.port}` },
})
}
}
Shell
Copy
Ask AI
cdktn deploy app Initializing the backend... app Initializing provider plugins... - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.14.0 app Terraform has been successfully initialized! ##... app No changes. Your infrastructure matches the configuration. app Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed. app app_frontend url = http://localhost:30001 app_backend url = http://localhost:30002
TypeScript
Copy
Ask AI
new MyStack(app, 'app-test', {
frontend: {
image: 'localhost:5000/nocorp-frontend:latest',
replicas: 4,
port: 30003,
app: 'myapp',
component: 'frontend',
environment: 'test',
},
backend: {
image: 'localhost:5000/nocorp-backend:latest',
replicas: 2,
port: 30004,
app: 'myapp',
component: 'backend',
environment: 'test',
},
})
Shell
Copy
Ask AI
cdktn deploy app-test app-test Initializing the backend... app-test Successfully configured the backend "local"! Terraform will automatically use this backend unless the backend configuration changes. app-test Initializing provider plugins... - Finding hashicorp/kubernetes versions matching "2.14.0"... app-test - Using hashicorp/kubernetes v2.14.0 from the shared cache directory app-test Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. ##... Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop ##... app-test kubernetes_service.app_frontend_service_C2863249 (app_frontend/service/service): Creating... kubernetes_service.app_backend_service_EAD583EF (app_backend/service/service): Creating... app-test kubernetes_deployment.app_backend_deployment_1A8B5520 (app_backend/deployment/deployment): Creating... app-test kubernetes_deployment.app_frontend_deployment_0EE98C72 (app_frontend/deployment/deployment): Creating... app-test kubernetes_service.app_frontend_service_C2863249 (app_frontend/service/service): Creation complete after 0s [id=default/myapp-frontend-test] app-test kubernetes_service.app_backend_service_EAD583EF (app_backend/service/service): Creation complete after 0s [id=default/myapp-backend-test] app-test kubernetes_deployment.app_frontend_deployment_0EE98C72 (app_frontend/deployment/deployment): Creation complete after 8s [id=default/myapp-frontend-test] app-test kubernetes_deployment.app_backend_deployment_1A8B5520 (app_backend/deployment/deployment): Creation complete after 8s [id=default/myapp-backend-test] app-test Apply complete! Resources: 4 added, 0 changed, 0 destroyed. app-test Outputs:
Shell
Copy
Ask AI
kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE myapp-backend-dev 1/1 1 1 46m myapp-backend-test 2/2 2 2 71s myapp-frontend-dev 3/3 3 3 60m myapp-frontend-test 4/4 4 4 71s
Clean up resources
Destroy the test stack.Shell
Copy
Ask AI
cdktn destroy app-test app-test Initializing the backend... app-test Initializing provider plugins... - Reusing previous version of hashicorp/kubernetes from the dependency lock file app-test - Using previously-installed hashicorp/kubernetes v2.14.0 app-test Terraform has been successfully initialized! ##... Plan: 0 to add, 0 to change, 4 to destroy. app-test Changes to Outputs: - app_backend_url_CAA2B50B = "http://localhost:30004" -> null - app_frontend_url_5DD99814 = "http://localhost:30003" -> null ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app-test ❯ Approve Applies the changes outlined in the plan. Dismiss Stop ##... app-test kubernetes_service.app_backend_service_EAD583EF (app_backend/service/service): Destruction complete after 0s app-test kubernetes_service.app_frontend_service_C2863249 (app_frontend/service/service): Destruction complete after 0s app-test Destroy complete! Resources: 4 destroyed.
Shell
Copy
Ask AI
cdktn destroy app app Initializing the backend... app Initializing provider plugins... - Reusing previous version of hashicorp/kubernetes from the dependency lock file app - Using previously-installed hashicorp/kubernetes v2.12.1 app Terraform has been successfully initialized! ##... Plan: 0 to add, 0 to change, 4 to destroy. Changes to Outputs: - app_frontend_url_FE3D723A = "http://localhost:30001" -> null - app_backend_url_91B41C22 = "http://localhost:30002" -> null ───────────────────────────────────────────────────────────────────────────── Saved the plan to: plan To perform exactly these actions, run the following command to apply: terraform apply "plan" Please review the diff output above for app ❯ Approve Applies the changes outlined in the plan. Dismiss Stop ##... app kubernetes_service.app_backend_service_EAD583EF (app_backend/service/service): Destruction complete after 0s app kubernetes_service.app_frontend_service_C2863249 (app_frontend/service/service): Destruction complete after 0s app Destroy complete! Resources: 4 destroyed.
Shell
Copy
Ask AI
kind delete cluster --name=cdktf-app Deleting cluster "cdktf-app" ...
Shell
Copy
Ask AI
docker stop local-registry local-registry
Shell
Copy
Ask AI
docker rm local-registry local-registry
Next steps
- Review how to structure CDKTN code with Constructs and Stacks.
- If you want a smaller starting point, begin with the Install tutorial or Build AWS infrastructure.