Clarte is your friendly neighbourhood French learning app, designed to not suck. It aims to make learning French clear, engaging, and maybe even a little bit fun. This setup includes a web frontend (built with Next.js), a backend API (built with NestJS), and a Postgres database to store all the good stuff.
This guide explains how to deploy the full Clarte stack using Kubernetes (k3s/k3d).
Make sure you have the following tools installed on your local machine:
- Git: To clone the repository.
- Docker Desktop: Required for running k3d and the containers locally. (Or Docker Engine on Linux).
- kubectl: The Kubernetes command-line tool. (Install Guide)
- k3d: The tool for running lightweight k3s clusters in Docker locally. (Install Guide)
For remote server deployment:
- A Linux server accessible via SSH.
- k3s installed and running on the server. (Install Guide)
- Ability to securely copy the
k3s.yaml
kubeconfig file from the server to your local machine. - (Optional but Recommended) A domain name and DNS configured to point to your server's IP address for proper Ingress setup.
Docker images for the clarte-web
frontend and clarte-api
backend are automatically built and pushed to GitHub Container Registry (GHCR) by GitHub Actions workflows located in .github/workflows/
. These workflows trigger on pushes to the main
branch. The Kubernetes manifests reference these images (e.g., ghcr.io/amirzhou/clarte-api:latest
).
Follow the steps for either local deployment (k3d) or remote server deployment (k3s).
This is great for testing and development.
-
Clone the Repository:
git clone https://github.com/AmirZhou/clarte.git cd clarte
-
Create k3d Cluster:
- We need to map port 80 on your host to the cluster's load balancer for Ingress. Choose a host port (e.g.,
80
if free, or8080
). - (Optional: If port 80 is busy, use the second command)
# Option A: Use host port 80 (if free) k3d cluster create clarte-local -p "80:80@loadbalancer" # Option B: Use host port 8080 (if 80 is busy) # k3d cluster create clarte-local -p "8080:80@loadbalancer"
- This command creates the cluster and automatically configures
kubectl
to use it. Verify withkubectl get nodes
.
- We need to map port 80 on your host to the cluster's load balancer for Ingress. Choose a host port (e.g.,
-
Modify Hosts File:
- To access the app via
http://clarte.local
, edit your computer's hosts file:- Windows:
C:\Windows\System32\drivers\etc\hosts
(Edit as Admin) - macOS/Linux:
/etc/hosts
(Usesudo
)
- Windows:
- Add this line:
127.0.0.1 clarte.local
- Save the file.
- To access the app via
-
Create Kubernetes Secret:
- Create the secret for Postgres using test/local credentials.
kubectl create secret generic postgres-secret \ --from-literal=POSTGRES_USER='your-user' \ --from-literal=POSTGRES_PASSWORD='your-password' # (Or use --from-file=... pointing to local .txt files if you prefer)
-
Apply Kubernetes Manifests:
- Apply all the configuration files from the
k8s
directory. The order generally doesn't strictly matter withapply -f
, but applying dependencies first is good practice.
# Apply Postgres components kubectl apply -f k8s/postgres-service.yaml kubectl apply -f k8s/postgres-statefulset.yaml # Wait for Postgres pod to be Running and Ready (1/1) echo "Waiting for Postgres pod to be ready..." kubectl wait --for=condition=ready pod -l app=postgres --timeout=300s # Apply the Migration Job kubectl apply -f k8s/migration-job.yaml # Check the Migration Job kubectl logs Job/clarte-api-migration # Apply API components kubectl apply -f k8s/api-service.yaml kubectl apply -f k8s/api-deployment.yaml # Wait for API and Web pods to attempt starting echo "Waiting for API and Web deployments..." # It may take around 10 minuts to populate the database. kubectl logs deploy/clarte-api # Run this command, make sure the progress hits 100% # Apply Web components kubectl apply -f k8s/web-service.yaml kubectl apply -f k8s/web-deployment.yaml # Wait for API and Web pods to attempt starting echo "Waiting for API and Web deployments..." sleep 15 # Give them a moment to start # Apply the Ingress rules kubectl apply -f k8s/ingress.yaml
- Apply all the configuration files from the
-
Monitor Deployment:
- Check the migration job status:
kubectl get jobs -w # Once created, check logs: kubectl logs job/<job-name>
- Check the status of all pods:
(Wait until
kubectl get pods -w
postgres-0
,clarte-api-...
, andclarte-web-...
pods areRunning
andREADY 1/1
)
- Check the migration job status:
-
Access the App:
- Open your browser.
- Navigate to:
http://clarte.local
(if you mapped host port 80)http://clarte.local:8080
(if you mapped host port 8080)
This deploys to your dedicated Linux server running k3s by running commands directly on the server.
-
SSH into your Server:
ssh your_user@your_server_ip
-
Install Prerequisites (if needed):
- Ensure k3s is installed and running.
- Install Git:
sudo apt update && sudo apt install git -y
- Install kubectl (if not bundled with your k3s or you need a specific version): Follow official Kubernetes instructions. Often, k3s makes
kubectl
available automatically. Verify withkubectl version
.
-
Clone the Repository (On the Server):
git clone https://github.com/AmirZhou/clarte.git cd clarte
-
Verify
kubectl
Configuration:- When running
kubectl
directly on the k3s server node, it should automatically use the correct configuration (typically found at/etc/rancher/k3s/k3s.yaml
). - Verify connection:
kubectl get nodes
(should show your server node, likely with the 'control-plane,master' role).
- When running
-
Create Kubernetes Secret (Using Production Credentials):
- Run this command directly on the server using strong, unique production credentials.
kubectl create secret generic postgres-secret \ --from-literal=POSTGRES_USER='YOUR_PROD_DB_USER' \ --from-literal=POSTGRES_PASSWORD='YOUR_STRONG_PROD_PASSWORD' # (Or use --from-file=... pointing to files you create securely on the server)
-
Apply Kubernetes Manifests:
- Apply all configurations from the
k8s
directory (which you cloned onto the server).
# Apply Postgres components kubectl apply -f k8s/postgres-service.yaml kubectl apply -f k8s/postgres-statefulset.yaml # Wait for Postgres pod to be Running and Ready (1/1) echo "Waiting for Postgres pod to be ready..." kubectl wait --for=condition=ready pod -l app=postgres --timeout=300s # Apply the Migration Job kubectl apply -f k8s/migration-job.yaml # Apply API components kubectl apply -f k8s/api-service.yaml kubectl apply -f k8s/api-deployment.yaml # Wait for API and Web pods to attempt starting echo "Waiting for API and Web deployments..." sleep 900 # It may take around 10 minuts to populate the database. # Apply Web components kubectl apply -f k8s/web-service.yaml kubectl apply -f k8s/web-deployment.yaml # Wait for API and Web pods to attempt starting echo "Waiting for API and Web deployments..." sleep 15 # Give them a moment to start # Apply the Ingress rules kubectl apply -f k8s/ingress.yaml
- Apply all configurations from the
-
Monitor Deployment:
- Check the migration job:
kubectl get jobs -w
,kubectl logs job/<job-name>
- Check all pods:
kubectl get pods -w
- Check the migration job:
-
Configure DNS & Access the App:
- (External Step) Ensure you have a DNS A record pointing your desired domain name (e.g.,
clarte.yourdomain.com
) to your server's public IP address. - (On Server) Update the
host:
field ink8s/ingress.yaml
fromclarte.local
toclarte.yourdomain.com
(e.g., usingnano
orvim
). - (On Server) Re-apply the ingress:
kubectl apply -f k8s/ingress.yaml
. - (Optional but Recommended) Set up TLS/HTTPS using Let's Encrypt, typically via annotations on the Ingress resource and configuring Traefik or cert-manager.
- (From Any Machine) Access your app via
http://clarte.yourdomain.com
(orhttps://
if you set up TLS).
- (External Step) Ensure you have a DNS A record pointing your desired domain name (e.g.,
Enjoy your clearly deployed Clarte app! ✨