Skip to content

Commit

Permalink
feat: offer deployment manifests
Browse files Browse the repository at this point in the history
Adds a basic Dockerfile for building the image containing this
application.
Additionally adds k8s manifest files that allow for deploying
the application to a Kubernetes cluster. Alongside with that
a deployment script is introduced that can be used to deploy
the application to an existing minikube instance for development
purposes.
  • Loading branch information
DiCanio committed Mar 18, 2024
1 parent e3c407a commit fce88a7
Show file tree
Hide file tree
Showing 11 changed files with 411 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
npm-debug.log
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ db.sqlite
.env
cache
.swc

k8s/tmp**
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM node:20.11-alpine3.19@sha256:c0a3badbd8a0a760de903e00cedbca94588e609299820557e72cba2a53dbaa2c
RUN mkdir -p /home/node/node-message-broker/node_modules && chown -R node:node /home/node/node-message-broker
WORKDIR /home/node/node-message-broker
COPY --chown=node:node package*.json .

USER node

RUN npm install

COPY --chown=node:node ./dist .

EXPOSE 3000

CMD [ "node", "index.js" ]
59 changes: 59 additions & 0 deletions k8s/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# k8s

> [!CAUTION]
> Files found in this directory should be used with caution and NOT in a production environment! They are mainly for showcasing purposes. So, adjust them as necessary before applying them to your cluster.
This directory contains:
- a deployment script (`deploy-to-minikube.sh`)
- k8s manifest files

## Prerequisites

### minikube

Make sure the following `minikube` addons are enabled before using this deployment solution:

- ingress
- registry
- storage-provisioner

You can enable addons using the following command:

```shell
minikube addons enable <addon>
```

For further information, see: [minikube addon docs](https://minikube.sigs.k8s.io/docs/commands/addons/).

### build artifact

Since the script builds a new Docker image on the fly before using it in the deployment, make sure that the application has been built using the following command in the root directory of the project:

```shell
npm run build
```


## Usage

The script will install a single message broker instance to an already existing `minikube` cluster. In order to use it make sure the following environment variables are set:

| ENV VAR | DESCRIPTION |
|---------|-------------|
| AUTH_JWKS_URL | URL to obtain JWKS from. Using keycloak this has the pattern `<KEYCLOAK_BASE_URL>/realms/<YOUR_REALM>/protocol/openid-connect/certs`. |
| HUB_AUTH_ROBOT_ID | ID of the robot account to be used. Needs to exist on the central side (hub) at `https://auth.privateaim.net/`. |
| ROBOT_SECRET | Associated secret of the robot account. |
| NODE_MESSAGE_BROKER_HOST | Host to be used for the message broker. It will be accessible under `message-broker.<HOST>.nip.io`. |
| NAMESPACE | Namespace to be used within the minikube cluster. |

Set the following optional environment variables for further configuration:

| ENV VAR | DESCRIPTION |
|---------|-------------|
| HUB_BASE_URL | Base URL of the central side (hub). Defaults to `https://api.privateaim.net`. |
| HUB_AUTH_BASE_URL | Base URL of the central side's (hub) auth provider. Defaults to `https://auth.privateaim.net`. |

After that simply call the script with:
```shell
./deploy-to-minikube
```
124 changes: 124 additions & 0 deletions k8s/deploy-to-minikube.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env bash

# Mandatory environment variables:
#
# - AUTH_JWKS_URL
# - HUB_AUTH_ROBOT_ID
# - ROBOT_SECRET
# - NODE_MESSAGE_BROKER_HOST
# - NAMESPACE

# Optional environment variables:
#
# - HUB_AUTH_BASE_URL
# - HUB_BASE_URL

BASE_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 || exit 1 ; pwd -P )"

if [[ -z "${AUTH_JWKS_URL}" || -z "${HUB_AUTH_ROBOT_ID}" || -z "${ROBOT_SECRET}" || -z "${NODE_MESSAGE_BROKER_HOST}" || -z "${NAMESPACE}" ]]; then
echo "One or more mandatory environment variables are not set!"
echo "Mandatory environment variables are:"
echo ""
echo " - AUTH_JWKS_URL"
echo " - HUB_AUTH_ROBOT_ID"
echo " - ROBOT_SECRET"
echo " - NODE_MESSAGE_BROKER_HOST"
echo " - NAMESPACE"
exit 1
fi

echo -n "Creating temporary working directory..."
WORK_DIR=`mktemp -d -p "${BASE_DIR}"`
if [ $? -ne 0 ]; then
echo "FAILED"
exit 2
else
echo "OK"
fi

echo -n "Copying k8s manifest files..."
for f in "${BASE_DIR}"/manifests/*.yml; do
cp "${f}" "${WORK_DIR}"
done
if [ $? -ne 0 ]; then
echo "FAILED"
exit 3
else
echo "OK"
fi

echo -n "Preparing broker deployment..."
sed -i -e "s#<AUTH_JWKS_URL>#${AUTH_JWKS_URL}#" \
-e "s#<HUB_AUTH_ROBOT_ID>#${HUB_AUTH_ROBOT_ID}#" \
-e "s#<HUB_AUTH_BASE_URL>#${HUB_AUTH_BASE_URL:-"https://auth.privateaim.net"}#" \
-e "s#<HUB_BASE_URL>#${HUB_BASE_URL:-"https://api.privateaim.net"}#" \
"${WORK_DIR}/broker-deployment.yml"
if [ $? -ne 0 ]; then
echo "FAILED"
exit 4
else
echo "OK"
fi

echo -n "Preparing hub auth secret..."
sed -i -e "s#<ROBOT_SECRET>#$(echo -n ${ROBOT_SECRET} | base64)#" \
"${WORK_DIR}/hub-auth-secret.yml"
if [ $? -ne 0 ]; then
echo "FAILED"
exit 5
else
echo "OK"
fi

echo -n "Preparing ingress..."
sed -i -e "s#<NODE_MESSAGE_BROKER_HOST>#${NODE_MESSAGE_BROKER_HOST}#" \
"${WORK_DIR}/ingress.yml"
if [ $? -ne 0 ]; then
echo "FAILED"
exit 6
else
echo "OK"
fi


echo -n "Deleting previous image..."
minikube image rm docker.io/flame/node-message-broker:latest >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "FAILED"
exit 7
else
echo "OK"
fi

echo -n "Creating Docker image..."
minikube image build -t docker.io/flame/node-message-broker:latest "${BASE_DIR}/.." >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "FAILED"
exit 8
else
echo "OK"
fi

echo -n "Applying manifest files..."
# TODO: make namespace adjustable!!!
minikube kubectl -- --namespace "${NAMESPACE}" apply -f "${WORK_DIR}/hub-auth-secret.yml" \
-f "${WORK_DIR}/broker-db-service.yml" \
-f "${WORK_DIR}/broker-db-statefulset.yml" \
-f "${WORK_DIR}/broker-service.yml" \
-f "${WORK_DIR}/broker-deployment.yml" \
-f "${WORK_DIR}/ingress.yml" >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "FAILED"
exit 9
else
echo "OK"
fi

echo -n "Deleting temporary working directory..."
rm -Rf "${WORK_DIR}"
if [ $? -ne 0 ]; then
echo "FAILED"
exit 10
else
echo "OK"
fi
12 changes: 12 additions & 0 deletions k8s/manifests/broker-db-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: node-message-broker-db
spec:
selector:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: database
app.kubernetes.io/part-of: flame
ports:
- port: 27017
targetPort: 27017
85 changes: 85 additions & 0 deletions k8s/manifests/broker-db-statefulset.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: node-message-broker-db
labels:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: database
app.kubernetes.io/part-of: flame
spec:
serviceName: "node-message-broker-db"
updateStrategy:
rollingUpdate:
maxUnavailable: 0
selector:
matchLabels:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: database
app.kubernetes.io/part-of: flame
replicas: 1
template:
metadata:
labels:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: database
app.kubernetes.io/part-of: flame
spec:
restartPolicy: "Always"
containers:
- name: node-message-broker-db
image: mongo:7.0.5@sha256:fcde2d71bf00b592c9cabab1d7d01defde37d69b3d788c53c3bc7431b6b15de8
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_DATABASE
value: "message-broker"
- name: TZ
value: "Europe/Berlin"
resources:
requests:
memory: "256Mi"
limits:
memory: "1Gi"
cpu: "1"
readinessProbe:
exec:
command:
- mongosh
- --eval
- 'db.runCommand("ping").ok'
- --quiet
failureThreshold: 3
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 15
initialDelaySeconds: 30
livenessProbe:
exec:
command:
- mongosh
- --eval
- 'db.runCommand("ping").ok'
- --quiet
failureThreshold: 3
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 15

volumeMounts:
- name: storage
mountPath: /data/db
volumeClaimTemplates:
- metadata:
name: storage
spec:
accessModes: ["ReadWriteMany"]
# We are not using this to make use of the default storage class
# This however, should be changed in the future.
# storageClassName:
resources:
requests:
storage: 100Mi
75 changes: 75 additions & 0 deletions k8s/manifests/broker-deployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-message-broker
labels:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: server
app.kubernetes.io/part-of: flame
spec:
revisionHistoryLimit: 3
selector:
matchLabels:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: server
app.kubernetes.io/part-of: flame
template:
metadata:
labels:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: server
app.kubernetes.io/part-of: flame
spec:
restartPolicy: "Always"
containers:
- name: node-message-broker
image: docker.io/flame/node-message-broker:latest
imagePullPolicy: "IfNotPresent"
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
ports:
- containerPort: 8080
env:
- name: SERVER_PORT
value: "8080"
- name: AUTH_JWKS_URL
value: <AUTH_JWKS_URL>
- name: MONGO_DB_URL
value: "mongodb://node-message-broker-db:27017"
- name: MONGO_DB_NAME
value: "message-broker"
- name: HUB_BASE_URL
value: <HUB_BASE_URL>
- name: HUB_AUTH_BASE_URL
value: <HUB_AUTH_BASE_URL>
- name: HUB_AUTH_ROBOT_ID
value: <HUB_AUTH_ROBOT_ID>
- name: HUB_AUTH_ROBOT_SECRET
valueFrom:
secretKeyRef:
name: hub-auth
key: robot-secret
# DO NOT USE THIS IN PRODUCTION!!! This is just for internal testing purposes.
- name: NODE_TLS_REJECT_UNAUTHORIZED
value: "0"
resources:
requests:
memory: "256Mi"
limits:
memory: "512Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: "/health"
port: 8080
initialDelaySeconds: 60
periodSeconds: 5
timeoutSeconds: 10
livenessProbe:
httpGet:
path: "/health"
port: 8080
periodSeconds: 10
timeoutSeconds: 10
12 changes: 12 additions & 0 deletions k8s/manifests/broker-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: node-message-broker
spec:
selector:
app.kubernetes.io/name: node-message-broker
app.kubernetes.io/component: server
app.kubernetes.io/part-of: flame
ports:
- port: 80
targetPort: 8080
Loading

0 comments on commit fce88a7

Please sign in to comment.