QuectoLink is a scalable and distributed URL shortener service that allows users to shorten long URLs into more manageable and shareable links. The name "Quecto" is derived from the term for the smallest unit in the metric system, reflecting the service's ability to efficiently shorten URLs.
- Shorten long URLs into concise and manageable links.
- Scalable architecture to handle large volumes of URL shortening requests.
- Distributed system for high availability and fault tolerance.
- Utilizes MERN stack (MongoDB, Express.js, React.js, Node.js) for web application development.
- Integration with Redis for caching and performance optimization.
- Utilizes ZooKeeper for distributed coordination and consensus.
- Nginx used for load balancing to distribute incoming traffic across multiple servers.
- Kubernetes integration for scaling and managing the containerized application in a production environment.
- Containerized with Docker for easy deployment and scalability.
- Implemented GitHub Actions for automatic deployment to virtual machines upon code changes, ensuring continuous integration and delivery.
- MERN Stack: MongoDB, Express.js, React.js, Node.js - for web application development.
- Redis: In-memory data structure store used for caching frequently accessed data.
- ZooKeeper: Distributed coordination service for maintaining configuration information, naming, and providing distributed synchronization.
- Nginx: High-performance web server and reverse proxy for load balancing.
- Kubernetes: Used for managing and scaling containerized services in production environments.
- Docker: Containerization platform for packaging the application and its dependencies into standardized units for deployment.
- GitHub Actions: Automated workflow tool integrated with GitHub repository for continuous integration and deployment, ensuring seamless deployment to virtual machines upon code changes.
I will walk you through setting up QuectoLink. We'll cover how to set up the project using npm, containerize it with Docker, and deploy it on Kubernetes using various tools like kubeadm, k3s, and k3d (Windows).
- Setting Up QuectoLink with npm
- Dockerizing QuectoLink
- Deploying with Kubernetes
- Conclusion
- References
To get started with QuectoLink locally using npm:
- Node.js and npm installed on your machine.
-
Clone the repository:
git clone https://github.com/programmingninjas/quectolink.git
-
Navigate to the project directory:
cd quectolink
-
Install dependencies in backend and frontend folder:
npm install
-
Update the environment variables in a
.env
file of backend folder:MONGO_URI=mongodb://localhost:27017/your_db_name PORT=5000 JWT_SECRET=your_jwt_secret
-
Start the backend:
npm run server
-
Start the frontend:
npm run dev
-
Open your browser and go to
http://localhost:3000
.
- Docker and Docker Compose installed.
-
Build Docker images for the frontend and backend:
Navigate to the respective directories and build the images using the provided Dockerfiles.
For the backend:
cd backend docker build -t quectolink-backend .
For the frontend:
cd frontend docker build -t quectolink-frontend .
-
Update your
docker-compose.yml
file to reference the newly built images:
services:
frontend:
image: quectolink-frontend
ports:
- "3000:3000"
depends_on:
- backend
backend:
image: quectolink-backend
ports:
- "5000:5000"
environment:
- MONGO_URI=mongodb://mongo:27017/your_db_name
- JWT_SECRET=your_jwt_secret
- PORT=5000
depends_on:
- mongo
- zookeeper
- cache
mongo:
image: mongo
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
cache:
image: redis:alpine
ports:
- "6379:6379"
zookeeper:
image: zookeeper
ports:
- "2181:2181"
volumes:
mongo-data:
-
Run
docker-compose
to start all services in detached mode:docker compose up -d
-
Check running containers to ensure everything is working properly:
docker ps
-
Access the application in your browser at
http://localhost:3000
.
Now let’s deploy QuectoLink in a Kubernetes cluster. We’ll cover kubeadm, k3s, and k3d for different environments.
kubeadm is a tool to bootstrap a Kubernetes cluster.
- A system with multiple nodes.
SSH into your Master server using the following command (replace the placeholders with your actual values):
ssh -i "your-key.pem" user@<MASTER-IP>
Disable the swap to ensure optimal Kubernetes performance.
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter
Configure sysctl parameters for Kubernetes networking:
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# Apply the sysctl parameters without rebooting
sudo sysctl --system
Verify that the necessary kernel modules and system variables are set:
lsmod | grep br_netfilter
lsmod | grep overlay
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
Install and configure containerd as the container runtime for Kubernetes. (Always use latest stable release)
# Download and install containerd
curl -LO https://github.com/containerd/containerd/releases/download/v1.7.14/containerd-1.7.14-linux-amd64.tar.gz
sudo tar Cxzvf /usr/local containerd-1.7.14-linux-amd64.tar.gz
# Setup containerd as a systemd service
curl -LO https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
sudo mkdir -p /usr/local/lib/systemd/system/
sudo mv containerd.service /usr/local/lib/systemd/system/
# Configure containerd and enable systemd cgroups
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
# Start containerd
sudo systemctl daemon-reload
sudo systemctl enable --now containerd
# Verify containerd service
systemctl status containerd
Install runc
, a low-level container runtime:
curl -LO https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64
sudo install -m 755 runc.amd64 /usr/local/sbin/runc
Install the CNI (Container Network Interface) plugins:
curl -LO https://github.com/containernetworking/plugins/releases/download/v1.5.0/cni-plugins-linux-amd64-v1.5.0.tgz
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.5.0.tgz
Install Kubernetes components using version 1.29
to allow for later upgrades:
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
# Add the Kubernetes package repository
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
# Install kubeadm, kubelet, and kubectl
sudo apt-get update
sudo apt-get install -y kubelet=1.29.6-1.1 kubeadm=1.29.6-1.1 kubectl=1.29.6-1.1 --allow-downgrades --allow-change-held-packages
sudo apt-mark hold kubelet kubeadm kubectl
Check the installed versions:
kubeadm version
kubelet --version
kubectl version --client
To configure crictl to work with containerd
:
sudo crictl config runtime-endpoint unix:///var/run/containerd/containerd.sock
To initialize the Kubernetes control plane with Flannel's default subnet for pod networking, use the following command on the master node. Be sure to replace <Master-IP>
with the Private IP address of the master node:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=<Master-IP> --node-name master
- Note: Ensure that your worker nodes are on the same subnet as the master node, or connected via a router if they are in different subnets. If you want to advertise it over a public IP (e.g., for a multi-region setup), you would use the public IP by adding
--control-plane-endpoint "PUBLIC_IP:PORT"
.
After the command completes, you will receive an output containing a join command for worker nodes. Save this command for later use when adding worker nodes. If you forget to you can use:
kubeadm token create --print-join-command
Prepare the kubeconfig file for kubectl
:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
helm upgrade --install ingress-nginx ingress-nginx --repo https://kubernetes.github.io/ingress-nginx --namespace ingress-nginx --create-namespace
ssh -i "your-key.pem" user@<WORKER-IP>
- Disable Swap
- Forward IPv4 and Enable iptables for Bridged Traffic
- Install Container Runtime (containerd)
- Install runc
- Install CNI Plugins
- Install
kubeadm
,kubelet
, andkubectl
- Configure
crictl
to work withcontainerd
Refer to the steps from the master node setup for detailed commands.
Once the worker node is configured, join it to the master using the token received after running kubeadm init
on the master node. Run the following command on the worker node (replace <TOKEN>
and <MASTER-IP>
with the values you saved):
sudo kubeadm join <MASTER-IP>:6443 --token <TOKEN> --discovery-token-ca-cert-hash sha256:<HASH>
After this, the worker node will join the cluster and the master will start managing it. You can verify the setup from the master node using:
kubectl get nodes
This will display all the nodes in your Kubernetes cluster.
k3s is a lightweight Kubernetes distribution.
- k3s installed.
-
Install k3s:
curl -sfL https://get.k3s.io | sh -
-
Use kubectl without sudo:
sudo chmod 644 /etc/rancher/k3s/k3s.yaml
-
Apply all the Yamls
k3d is a tool to run k3s clusters inside Docker containers.
- Docker Desktop installed.
-
Install k3d using Chocolatey:
choco install k3d
-
Create a k3d cluster:
k3d cluster create mycluster --servers 1 --agents 2
-
Apply all the Yamls
QuectoLink is a powerful, scalable URL shortener service that can be easily set up using npm, Docker, and Kubernetes. Whether you're deploying locally or in a production environment, the flexibility of QuectoLink ensures a smooth and efficient deployment process. While using the local environment if you don't have the Public I.P you can use kubectl port-forwarding to port forward ingress port to your local machine or patch a service using type NodePort.