Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
404cb9f
include a proxy endpoint that routes traffic to the node-server
dprotaso Oct 13, 2025
4389e55
reduce frontend nextjs image size to ~300MB
dprotaso Oct 13, 2025
1610987
use port 80 for frontend k8s service
dprotaso Oct 13, 2025
adb4222
include node about checking the tunnels for connectivity
dprotaso Oct 13, 2025
6531767
fix non-websocket backend requests
dprotaso Oct 13, 2025
f252b0a
sync frontend solution with changes
dprotaso Oct 13, 2025
238bee0
Minor tweaks to section 2
dprotaso Oct 13, 2025
0a1f21f
fix setup.sh script and update solution.sh script
dprotaso Oct 14, 2025
8386925
remove actual webhook url from docs
dprotaso Oct 14, 2025
ec7f62a
fix ports on env setup since we're not using localhost anymore
dprotaso Oct 14, 2025
c060a07
when creating the function include the type so invocation works
dprotaso Oct 14, 2025
fefea9f
fix indentation and kubectl log line
dprotaso Oct 14, 2025
8b33791
don't use localhost anymore to access the frontend website
dprotaso Oct 14, 2025
5886693
fix indentation on page 7
dprotaso Oct 14, 2025
fe2efe6
quote the camel-k installation so it works on zsh
dprotaso Oct 14, 2025
9f5414f
delete the correct unused image
dprotaso Oct 14, 2025
b4f730e
use the default frontend image
dprotaso Oct 14, 2025
f9501dd
Update code-samples/eventing/bookstore-sample-app/start/slack-sink/ap…
dprotaso Oct 15, 2025
7dd0914
shore up bash scripts
dprotaso Oct 15, 2025
0e46684
add log line to remind user to ensure tunnels/cloud-provider-kind is …
dprotaso Oct 15, 2025
2f6cd36
just suggest using KinD because it's networking is simpler
dprotaso Oct 16, 2025
638be0e
update get pods output to reflect kind
dprotaso Oct 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions code-samples/eventing/bookstore-sample-app/solution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ Here's an overview of the components in the solution:

## Running the Solution

1. Have a locally running Kubernetes cluster e.g. [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation) or [Minikube](https://minikube.sigs.k8s.io/docs/start).
1. Have a locally running container registry, e.g. [Kind registry setup](https://kind.sigs.k8s.io/docs/user/local-registry/) or [Minikube registry setup](https://minikube.sigs.k8s.io/docs/handbook/registry/#enabling-insecure-registries).
1. Have a locally running Kubernetes cluster e.g. [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/#installation).
1. Have a locally running container registry, e.g. [Kind registry setup](https://kind.sigs.k8s.io/docs/user/local-registry/).
1. Install all the prerequisites and deploy the entire solution using the `solution.sh` script:

```sh
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Use a base image with Node.js LTS
FROM node:lts-alpine
FROM node:lts-alpine AS builder

ENV NEXT_TELEMETRY_DISABLED=1

# Set the working directory inside the container
WORKDIR /app
Expand All @@ -16,8 +18,25 @@ COPY . .
# Build the Next.js application
RUN npm run build

FROM node:lts-alpine AS runner

WORKDIR /app

# Set environment variables for production
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

# Expose the port your app runs on
EXPOSE 3000
EXPOSE 8080

ENV PORT=8080


# Define the command to run your app
CMD ["npm", "run", "start"]
CMD ["node", "server.js"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import {WebSocket, WebSocketServer} from 'ws';
import { NextRequest, NextResponse } from 'next/server';


export async function GET(
req: NextRequest,
{ params }: { params: Promise<{ slug: string }> }
) {
const { slug } = await params // 'a', 'b', or 'c'
return proxyRequest(req, slug);
}

export async function POST(
req: NextRequest,
{ params }: { params: Promise<{ slug: string }> }
) {
const { slug } = await params // 'a', 'b', or 'c'
return proxyRequest(req, slug);
}

export async function PUT(
req: NextRequest,
{ params }: { params: Promise<{ slug: string }> }
) {
const { slug } = await params // 'a', 'b', or 'c'
return proxyRequest(req, slug);
}

export async function DELETE(
req: NextRequest,
{ params }: { params: Promise<{ slug: string }> }
) {
const { slug } = await params // 'a', 'b', or 'c'
return proxyRequest(req, slug);
}

async function proxyRequest(req: NextRequest, slug: string) {
const BACKEND_URL = (process.env.BACKEND_URL || `http://node-server-svc.${process.env.POD_NAMESPACE}.svc.cluster.local`) + '/' + slug;

const backendResponse = await fetch(BACKEND_URL, {
method: req.method,
headers: {
...Object.fromEntries(req.headers),
host: new URL(BACKEND_URL).host,
},
body: req.body ? req.body : undefined,
duplex: "half",
} as any);

// Clone the response and return it
const data = await backendResponse.arrayBuffer();
return new NextResponse(data, {
status: backendResponse.status,
headers: backendResponse.headers,
});
}

export function UPGRADE(
client: WebSocket,
server: WebSocketServer,
request: NextRequest,
context: import('next-ws/server').RouteContext<'/backend/[slug]'>,
) {
const slug = context.params?.slug
console.log('Client connected to /backend/' + slug)

// Backend server URL - replace with your actual backend server
const BACKEND_URL = (process.env.BACKEND_WS_URL || `ws://node-server-svc.${process.env.POD_NAMESPACE}.svc.cluster.local`) + '/' + slug;

console.log('Backend URL:', BACKEND_URL);

let backendConnection: WebSocket | null = null;
let isClientClosed = false;
let isBackendClosed = false;

// Connect to backend server
try {
backendConnection = new WebSocket(BACKEND_URL);

backendConnection.on('open', () => {
console.log('Connected to backend server');
});

backendConnection.on('message', (message) => {
if (!isClientClosed) {
client.send(message.toString());
}
});

backendConnection.on('close', (err) => {
console.log('Backend connection closed', err);
isBackendClosed = true;
if (!isClientClosed) {
client.close();
}
});

backendConnection.on('error', (error) => {
console.error('Backend connection error:', error);
if (!isClientClosed) {
client.close();
}
});

} catch (error) {
console.error('Failed to connect to backend:', error);
client.close();
return;
}

// Handle messages from client
client.on('message', (message) => {
if (backendConnection && !isBackendClosed) {
backendConnection.send(message.toString());
}
});

// Handle client disconnect
client.once('close', () => {
console.log('A client disconnected');
isClientClosed = true;
if (backendConnection && !isBackendClosed) {
backendConnection.close();
}
});

// Handle client errors
client.on('error', (error) => {
console.error('Client connection error:', error);
isClientClosed = true;
if (backendConnection && !isBackendClosed) {
backendConnection.close();
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
<html lang='en'>
<html lang='en' suppressHydrationWarning>
<body className={inter.className}>{children}</body>
</html>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ const CommentForm = () => {
setEverSubmit(true);
setResponseSuccess("unknown");

fetch("http://localhost:8080/add", {
fetch(`http://${window.location.host}/backend/add`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const CommentList = ({setStatus}) => {
const [comments, setComments] = useState([]);

useEffect(() => {
const ws = new WebSocket("ws://localhost:8080/comments");
const ws = new WebSocket(`ws://${window.location.host}/backend/comments`);

ws.onmessage = (event) => {
const newComments = JSON.parse(event.data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ spec:
- name: bookstore-frontend
image: ghcr.io/knative/bookstore-frontend:latest
ports:
- containerPort: 3000
- containerPort: 8080
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace

---
apiVersion: v1
Expand All @@ -27,7 +32,8 @@ metadata:
name: bookstore-frontend-svc
spec:
ports:
- port: 3000
- port: 80
targetPort: 8080
selector:
app: bookstore-frontend
type: LoadBalancer
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {
output: 'standalone',
};

export default nextConfig;
Loading
Loading