Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sample App: Adding the db service #5909

Merged
merged 13 commits into from Apr 10, 2024
@@ -0,0 +1,20 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: sql-configmap
data:
sample.sql: |
CREATE DATABASE bookstore;
CREATE TABLE IF NOT EXISTS book_reviews(
id SERIAL PRIMARY KEY,
post_time timestamp NOT NULL,
content TEXT NOT NULL,
sentiment TEXT,
CONSTRAINT sentiment_check CHECK (sentiment IN ('positive', 'negative', 'neutral'))
);

INSERT INTO book_reviews (post_time, content, sentiment) VALUES
('2020-01-01 00:00:00', 'This book is great!', 'positive'),
('2020-01-02 00:02:00', 'This book is terrible!', 'negative'),
('2020-01-03 00:01:30', 'This book is okay.', 'neutral'),
('2020-01-04 00:00:00', 'Meh', 'neutral');
@@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: postgresql-secret
type: Opaque
data:
POSTGRES_DB: bXlkYXRhYmFzZQ==
POSTGRES_USER: bXl1c2Vy
POSTGRES_PASSWORD: bXlwYXNzd29yZA==
@@ -0,0 +1,10 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgresql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
@@ -0,0 +1,42 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql
spec:
replicas: 1
selector:
matchLabels:
app: postgresql
template:
metadata:
labels:
app: postgresql
spec:
containers:
- name: postgresql
image: quay.io/enterprisedb/postgresql
env:
- name: POSTGRES_DB
valueFrom:
secretKeyRef:
name: postgresql-secret
key: POSTGRES_DB
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgresql-secret
key: POSTGRES_USER
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgresql-secret
key: POSTGRES_PASSWORD
ports:
- containerPort: 5432
volumeMounts:
- name: postgresql-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgresql-storage
persistentVolumeClaim:
claimName: postgresql-pvc
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Service
metadata:
name: postgresql
spec:
ports:
- port: 5432
selector:
app: postgresql
type: NodePort
@@ -0,0 +1,37 @@
apiVersion: batch/v1
kind: Job
metadata:
name: postgresql-job
spec:
ttlSecondsAfterFinished: 50
template:
spec:
containers:
- name: postgresql-client
image: quay.io/enterprisedb/postgresql
command: ["psql", "-h", "postgresql", "-U", "myuser", "-d", "mydatabase", "-f", "/sql/sample.sql"]
env:
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: postgresql-secret
key: POSTGRES_PASSWORD
- name: PGUSER
valueFrom:
secretKeyRef:
name: postgresql-secret
key: POSTGRES_USER
- name: PGDATABASE
valueFrom:
secretKeyRef:
name: postgresql-secret
key: POSTGRES_DB
volumeMounts:
- name: sql-volume
mountPath: /sql
restartPolicy: Never
volumes:
- name: sql-volume
configMap:
name: sql-configmap
backoffLimit: 5
14 changes: 14 additions & 0 deletions code-samples/eventing/bookstore-sample-app/db-service/sample.sql
@@ -0,0 +1,14 @@
CREATE DATABASE bookstore;
CREATE TABLE IF NOT EXISTS book_reviews(
id SERIAL PRIMARY KEY,
post_time timestamp NOT NULL,
content TEXT NOT NULL,
sentiment TEXT,
CONSTRAINT sentiment_check CHECK (sentiment IN ('positive', 'negative', 'neutral'))
);

INSERT INTO book_reviews (post_time, content, sentiment) VALUES
('2020-01-01 00:00:00', 'This book is great!', 'positive'),
('2020-01-02 00:02:00', 'This book is terrible!', 'negative'),
('2020-01-03 00:01:30', 'This book is okay.', 'neutral'),
('2020-01-04 00:00:00', 'Meh', 'neutral');
108 changes: 95 additions & 13 deletions code-samples/eventing/bookstore-sample-app/db/README.md
@@ -1,26 +1,108 @@
# Bookstore Database
# Database Service for Bookstore
To successfully launch the Bookstore sample application, it's essential to set up a dedicated database populated with specific sample data. This guide provides both the schema for the database and the initial data you'll need to get started.

1. Database Schema
2. Sample Data
In this tutorial, we'll embark on creating a PostgreSQL database using Kubernetes (K8s) StatefulSets and populating it with the sample data provided.

## 1. Database Schema
You might wonder, "Why not leverage Knative Serving to dynamically scale the database service in response to traffic demands?" We'll delve into the optimal scenarios for employing Knative Serving and when it's advantageous for our database service.

### BookReviews Table
## What does the final deliverable look like?
Our goal is to deploy a PostgreSQL pod within Kubernetes, loaded with the sample data outlined in the accompanying SQL file. This pod will serve as the foundational database service for our bookstore application.

## Overview
### The Database Schema
The BookReviews table contains all reviews made on the bookstore website.

See the columns of the BookReviews table below:
* ID (serial) - Primary Key
* post_time (datetime) - Posting time of the comment
* content (text) - The contents of the comment
* sentiment (text) - The sentiment results (currently, the values it could take on are 'positive' or 'neutral' or 'negative')

## 2. Sample Data
* `ID (serial)` - Primary Key
* `post_time (datetime)` - Posting time of the comment
* `content (text)` - The contents of the comment
* `sentiment (text)` - The sentiment results (currently, the values it could take on are 'positive' or 'neutral' or 'negative')

### BookReviews Table
### The Sample Data
The sample rows inserted for the BookReviews table are shown below:
| id | post_time | content | sentiment |
|----|---------------------|------------------------------|-----------|
| 1 | 2020-01-01 00:00:00 | This book is great! | positive |
| 2 | 2020-01-02 00:02:00 | This book is terrible! | negative |
| 3 | 2020-01-03 00:01:30 | This book is okay. | neutral |
| 4 | 2020-01-04 00:00:00 | Meh | neutral |
| 4 | 2020-01-04 00:00:00 | Meh | neutral |

## Implementation

### Step 1: Acquire Necessary Files from the Repository
The essential files for setting up your database are located within the `db` directory of our repository. Please download these files to proceed.

### Step 2: Deploying the PostgreSQL Database
To deploy the PostgreSQL database and populate it with the provided sample data, you'll apply a series of Kubernetes deployment files. Ensure you're positioned in the `code-sample` directory and not within the `db` subdirectory for this operation.

Within this directory, you will find 6 YAML files, each serving a distinct purpose in the setup process:
- `100-create-configmap.yaml`: Generates a ConfigMap including the SQL file for database initialization.
- `100-create-secret.yaml`: Produces a Secret holding the PostgreSQL database password.
- `100-create-volume.yaml`: Creates both a PersistentVolume and a PersistentVolumeClaim for database storage.
- `200-create-postgre.yaml`: Establishes the StatefulSet for the PostgreSQL database.
- `300-expose-service.yaml`: Launches a Service to expose the PostgreSQL database externally.
- `400-create-job.yaml`: Executes a Job that populates the database with the sample data.

Execute the command below to apply all configuration files located in the `db` directory:
```bash
kubectl apply -f db
```
The filenames prefixed with numbers dictate the application order, ensuring Kubernetes orchestrates the resource setup accordingly.

### Step 3: Confirming the Deployment
Following the application of the deployment files, initialization of the database may require some time. Monitor the deployment's progress by executing:
```bash
kubectl get pods

```
A successful deployment is indicated by the `Running` state of the `postgresql-0` pod, as shown below:
```bash
NAMESPACE NAME READY STATUS RESTARTS AGE
default postgresql-0 1/1 Running 0 1m
```
Upon observing the pod in a `Running` state, access the pod using the command:
```bash
kubectl exec -it postgresql-0 -- /bin/bash

```
Inside the pod, connect to the database with:
```bash
psql -U myuser -d mydatabase
```
A successful connection will present you with:
```bash
mydatabase=#
```
To verify the initialization of the `BookReviews` table, execute:
```
mydatabase=# \dt
```
If the output lists the `BookReviews` table as follows, your database has been correctly initialized:
```bash
List of relations
Schema | Name | Type | Owner
--------+--------------+-------+--------
public | book_reviews | table | myuser
(1 row)
```

## Question & Discussion
1. Why did we choose to deploy our PostgreSQL database using a StatefulSet instead of a Knative Service?

We use [StatefulSet](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) for databases instead of Knative Service mainly because databases need to remember data (like a notebook that keeps your notes). StatefulSets are good at remembering things because they can save data and have a special name and place where they live. This is very important for databases.

Knative Services are more like notebooks that you use and then throw away when you're done. They're great for tasks that don't need to keep data for a long time. You can make them go away when you don't need them and come back when you do. But databases need to always remember information, so they can't just disappear and come back.

Also, databases often talk in their own special language, not the usual web language (HTTP) that Knative Services are really good at understanding. Because of this, Knative Services aren't the best choice for databases. That's why we choose StatefulSet for databases in Kubernetes.

---
Note box: However, Knative Service supports Volumes and Persistent Volumes, which can be used to store data. You can read more [here](https://knative.dev/docs/serving/services/storage/) about how to use Volumes and Persistent Volumes with Knative Services specially for your use case.

---
Comment on lines +98 to +101
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the way to format a "note box"?

Copy link
Member Author

@Leo6Leo Leo6Leo Apr 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh it is a note to myself. I will edit it when we are ready to render the tutorial to pages. The issue has been created to track this #5938


2. When should I use Knative Service, and what would be the best use case for it?

You can read more about the best use cases for Knative Service [here](https://knative.dev/docs/serving/samples/)!
Comment on lines +103 to +105
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the samples page describes the point here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no page that describes the usage for the sample usage of Knative Service. Adding the new page or edit the current existing page to list the few sample usage is my thought:

  • E-commerce websites during sales events: traffic can spike a lot during sales events or holiday seasons. Knative Service can automatically scale the backend services up or down based on demand, ensuring that the website remains working.

  • Real-time analytics and monitoring: In IoT or data analytics applications, Knative can manage services that process data streams in real time. For example, a company monitoring environmental sensors across a city could use Knative to scale up data processing services as the volume of sensor data spikes.

  • ML model serving: serving different models based on user requirements or experimenting with A/B testing of models. It allows for the deployment of many revisions of a model and dynamically scales these services based on the request load!

  • Microservices and APIs: for those who use microservices architecture, Knative service provides a way to deploy and manage serverless APIs that scale automatically with usage. This is particularly useful for APIs with different traffic patterns

plz correct me if any of these are not accurate or may not be the best use case of knative service.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, those are accurate, however, my point is that we can have a dedicated page for this vs being part of something unrelated, in this page, we can stay concise and link to the dedicated page on "when to use ksvc vs when not to use ksvc"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that we don't have such content / page, we can add it later as necessary


## Conclusion
By following this guide, you have successfully deployed a PostgreSQL server on a Kubernetes cluster, set up persistent storage, and initialized your database using a Kubernetes job. Congratulations! Your bookstore now has the database service.
Comment on lines +107 to +108
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually, I think this needs a link to next section?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! In all parts of the tutorial, it will have the link navigate to the next section at the bottom to make sure the reading experience is good!