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
.envfile 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.ymlfile 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-composeto 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/fstabcat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilterConfigure 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 --systemVerify 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_forwardInstall 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 containerdInstall 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/runcInstall 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.tgzInstall 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 kubectlCheck the installed versions:
kubeadm version
kubelet --version
kubectl version --clientTo configure crictl to work with containerd:
sudo crictl config runtime-endpoint unix:///var/run/containerd/containerd.sockTo 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-commandPrepare 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/configkubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.ymlhelm upgrade --install ingress-nginx ingress-nginx --repo https://kubernetes.github.io/ingress-nginx --namespace ingress-nginx --create-namespacessh -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
crictlto 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 nodesThis 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.