When starting a project, it is best to begin with an idea and implement it as simply as possible to get it to market quickly. I am not doing that.
I was inspired to make a project that was at least complicated enough that I could use Kubernetes in production, have to think about scaling, and :optimistically add Consul to the deployment. I work on Consul’s integration with Kubernetes, but I’ve never operated a production Kubernetes cluster. I think I should.
Today, I had the idea for this sufficiently complicated project that was still simple enough that I could build it on my own and write about it.
GradientHub
GradientHub is a social network where users can create and share gradients. Gradients are a very popular part of web design today and I think this is a fun way to play with that.
I like gradients as something users can create and display because I don’t have to worry about users uploading photos which are hard to store and vet for inappropriate content.
I registered the domain gradienthub.art
for $4/year from Namecheap. Other domains were closer to $36/year and above and I just didn’t want to spend that money up front.
Architecture
The architecture here is the real goal. I’m making this more complicated than it needs to be so I can learn. I’m going to start with a React frontend using Next.js. This will be supported by three backend services:
- Users: manages user profiles and which gradients they have made or liked.
- Gradients: manages gradients, loading them from the database and showing users who’ve liked them. This can also be a caching layer.
- Generator: generates random gradients.
I am going to use PostgreSQL as my database. I’ll use a managed instance outside of Kubernetes.
Getting something shipped
I believe the best way to get work shipped is to start it out with a pipeline deploying into a production environment. This way I know from the start how the project behaves in a production environment. I have had issues before with doing so much development locally that I end up with something I have to modify in unintuitive ways in order to get it to production.
My first task then is to get a base layer frontend, containerize it, and ship it to a Kubernetes cluster.
Setting up Kubernetes
I decided to use Google Cloud Platform to run my Kubernetes cluster. Just because.
I set up the cluster in us-east
and set it to use the release channel Kubernetes. I’m doing this by clicking through the web UI. I should be doing this with Terraform. Maybe I can formalize a TF file for this configuration later.
I’m not quite sure what the cost will be for this deployment. I’m setting up a pricing alert to let me know if the cost exceeds $20/month.
Starting a Next.js Project
I am going to create a base Next.js project with Tailwind and TypeScript. I love TypeScript for frontend projects because it saves me from creating silly bugs.
I start off with
npx create-next-app@latest --ts
Yay!
Using TailwindCSS, I made a splash screen.
<div className="pt-40 flex flex-col items-center justify-center">
<h1 className="mb-4 text-7xl font-semibold text-transparent bg-clip-text bg-gradient-to-tr from-pink-500 via-red-500 to-yellow-500">
GradientHub
</h1>
<p>This is a work in progress.</p>
<p>
Check the{" "}
<a
href="https://github.com/t-eckert/gradienthub"
target="_blank"
rel="noopener noreferrer"
className="font-medium bg-clip-text bg-gradient-to-tr from-pink-500 via-red-500 to-yellow-500 hover:text-transparent transition"
>
GitHub repository
</a>{" "}
for more info.
</p>
</div>
Containerizing
I’m going to containerize the frontend service and push it to DockerHub. I pulled the Dockerfile and configuration from the NextJS with Docker example.
I built the image and pushed it to DockerHub as tecke/gradienthub-frontend
.
Deploying to Kubernetes
Now I need to tell Kubernetes to run 3 pods with that image. I connected the Google Cloud Kubernetes cluster to kubectl
. Now I need to write a deployment file and apply it to the cluster.
Here is the frontend.yaml
deployment file.
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
labels:
app: gradienthub-frontend
spec:
replicas: 3
selector:
matchLabels:
app: gradienthub-frontend
template:
metadata:
labels:
app: gradienthub-frontend
spec:
containers:
- name: frontend
image: tecke/gradienthub-frontend:latest
ports:
- containerPort: 3000
I applied the deployment and three replicas came right up!
Next, I need to create a Service to get a fixed IP to route requests to the pods. Eventually, I want to set all this up with the Consul API Gateway using the tech preview.
Here is frontend-service.yaml
.
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
type: LoadBalancer
selector:
app: gradienthub-frontend
ports:
- port: 80
targetPort: 3000
Deploying the Service of type LoadBalancer gave me a public IP of 34.75.24.253
.
I was able to visit the site in the browser! That’s enough for the first day.