Ok, let's say you need to test ingress changes and want fast feedback, and don't have access to actual k8s cluster. What would you do?
Kind for the rescue
Kind is just one of the options. It could be Minikube, Docker Desktop, K3s, Microk8s, etc
My goal is just share the steps I did to solve my problem, to others with similar needs and my future self.
1. First, a node app
Nothing fancy, just the basic to test:
a. server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT ?? 4000;
app.get('/*', (req, res) => {
res.json({
date: new Date(),
});
});
app.listen(PORT, () => {
console.log('Server started');
});
b. package.json
{
"scripts": {},
"dependencies": {
"express": "^4.21.1"
}
}
c. Dockerfile
FROM node:23
RUN mkdir -p /app
WORKDIR /app
COPY package.json ./
RUN npm install
COPY server.js ./
ENV PORT=4000
CMD ["node", "/app/server.js"]
Then build an image with something like docker build --quiet . -t app:local
2. The cluster
# Install kind on mac
brew install kind
# Create the cluster with custom config
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
EOF
# Install nginx
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml --context kind-kind
# Make sure it is working
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s --context kind-kind
3. deploy the app
a. publish image to the cluster:
kind load docker-image app:local
b. create pod, service, ingress: just save it in a file (e.g. k8s.yaml)
apiVersion: v1
kind: Service
metadata:
name: node-app
labels:
app: node-app
spec:
type: ClusterIP
ports:
- port: 80
targetPort:
protocol: TCP
name: http
selector:
app: node-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-app
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2
maxUnavailable: 0
selector:
matchLabels:
app: node-app
template:
metadata:
labels:
app: node-app
spec:
serviceAccountName: default
securityContext: null
containers:
- name: node-app
image: 'app:local'
env:
- name: PORT
value: '80'
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: node-app
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: 'node-app.com'
http:
paths:
- backend:
service:
name: node-app
port:
number: 80
pathType: ImplementationSpecific
c. apply the changes:
kubectl apply -f k8s.yaml --context kind-kind
4. Testing
a. with curl
curl --url http://localhost/test --header 'HOST: node-app.com'
or
b. with /etc/hosts
- Add
127.0.0.1 node-app.com
to/etc/hosts
- Access node-app.com on any browser
5. Done?
So, destroy the cluster to release memory:
kind delete cluster
So...
If you tried it and worked (or not), pls let me know.
For me it worked, I hope it help others and my future self