Terraform Course Labs

Deploying a TypeScript Stack on K3s with Terraform

This guide will walk you through the process of setting up and deploying a full-stack TypeScript application on a local Kubernetes (k3s) cluster, using Terraform for infrastructure management.

Table of Contents

  1. Prerequisites
  2. Project Structure
  3. Setting Up the Local Environment
  4. Frontend Setup (React with TypeScript)
  5. Backend Setup (Node.js with TypeScript)
  6. Database Setup (PostgreSQL)
  7. Containerization with Docker
  8. Infrastructure as Code with Terraform
  9. Deployment Process
  10. Testing the Application
  11. Troubleshooting

Prerequisites

Ensure you have the following installed on your local machine:

Project Structure

Create the following directory structure:

project-root/
├── frontend/
├── backend/
├── terraform/
└── scripts/

Setting Up the Local Environment

  1. Install k3s:
curl -sfL https://get.k3s.io | sh -
  1. Configure kubectl:
mkdir ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER:$USER ~/.kube/config

Frontend Setup (React with TypeScript)

  1. Create a new React app with TypeScript:
npx create-react-app frontend --template typescript
cd frontend
  1. Install additional dependencies:
npm install axios
  1. Replace the contents of src/App.tsx with the provided React component code.

Backend Setup (Node.js with TypeScript)

  1. Set up a new Node.js project with TypeScript:
mkdir backend && cd backend
npm init -y
npm install express pg cors
npm install --save-dev typescript @types/express @types/pg @types/cors ts-node
npx tsc --init
  1. Update tsconfig.json with the provided configuration.

  2. Create src/server.ts with the provided Node.js server code.

  3. Update package.json scripts as shown in the original document.

Database Setup (PostgreSQL)

We’ll use a PostgreSQL container in our k3s cluster. The setup will be handled by Terraform in later steps.

Containerization with Docker

  1. Create a Dockerfile in the frontend directory with the provided Dockerfile content.

  2. Create a Dockerfile in the backend directory with the provided Dockerfile content.

  3. Build the Docker images:

cd frontend
docker build -t frontend:latest .
cd ../backend
docker build -t backend:latest .

Infrastructure as Code with Terraform

  1. In the terraform directory, create main.tf with the provided Terraform configuration.

Deployment Process

  1. Navigate to the project root directory.

  2. Initialize Terraform:

cd terraform
terraform init
  1. Apply the Terraform configuration:
terraform apply
  1. Initialize the PostgreSQL database:
kubectl exec -it -n myapp $(kubectl get pods -n myapp -l app=postgres -o jsonpath='{.items[0].metadata.name}') -- psql -U postgres -d myapp -c "CREATE TABLE IF NOT EXISTS messages (id SERIAL PRIMARY KEY, text TEXT NOT NULL);"

Testing the Application

  1. Access the frontend: Open a web browser and navigate to http://localhost:30080

  2. Test the interaction:

    • You should see the React frontend with a message from the server (initially “No messages yet”).
    • Enter a new message in the input field and click “Submit”.
    • The new message should be displayed after submission.

Troubleshooting

If you encounter issues:

  1. Check pod status:
    kubectl get pods -n myapp
    
  2. View pod logs:
    kubectl logs -n myapp <pod-name>
    
  3. Access the backend directly:
    kubectl port-forward -n myapp service/backend 3000:3000
    

    Then, in another terminal:

    curl http://localhost:3000/api/message
    
  4. Check database connectivity:
    kubectl exec -it -n myapp <postgres-pod-name> -- psql -U postgres -d myapp -c "SELECT * FROM messages;"
    
  5. Review Terraform state:
    cd terraform && terraform show
    
  6. For TypeScript-specific issues:
    • Check compilation errors:
      cd frontend && npm run build
      cd ../backend && npm run build
      
    • Verify TypeScript configs:
      cat tsconfig.json
      

Remember, without Ansible, you’ll need to perform these steps manually and ensure all prerequisites are installed on your system. This process requires more direct interaction but gives you more control over each step of the deployment.