diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml new file mode 100644 index 0000000..29831d2 --- /dev/null +++ b/.github/workflows/frontend.yaml @@ -0,0 +1,39 @@ +name: Oktopus Frontend + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build-frontend: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - + name: Build Docker image + run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/frontend:latest -f frontend/build/Dockerfile frontend + - + name: Push Docker image to Docker Hub + run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/mqtt:latest + diff --git a/.github/workflows/mqtt.yaml b/.github/workflows/mqtt.yaml new file mode 100644 index 0000000..a3d5d91 --- /dev/null +++ b/.github/workflows/mqtt.yaml @@ -0,0 +1,39 @@ +name: Oktopus MQTT Broker + +# Controls when the action will run. Triggers the workflow on push or pull request +# events but only for the master branch +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build-mqtt: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - + name: Build Docker image + run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/mqtt:latest -f backend/services/mtp/mqtt/build/Dockerfile backend/services/mtp/mqtt + - + name: Push Docker image to Docker Hub + run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/mqtt:latest + diff --git a/backend/services/mtp/mqtt/build/Dockerfile b/backend/services/mtp/mqtt/build/Dockerfile index 2d59c5e..6a912db 100644 --- a/backend/services/mtp/mqtt/build/Dockerfile +++ b/backend/services/mtp/mqtt/build/Dockerfile @@ -5,4 +5,4 @@ RUN CGO_ENABLED=0 GOOS=linux go build -o mqtt cmd/mqtt/main.go FROM alpine:3.14@sha256:0f2d5c38dd7a4f4f733e688e3a6733cb5ab1ac6e3cb4603a5dd564e5bfb80eed COPY --from=builder /app/mqtt / -ENTRYPOINT ["/mqtt"] \ No newline at end of file +ENTRYPOINT ["/mqtt"] diff --git a/deploy/kubernetes/README.md b/deploy/kubernetes/README.md new file mode 100644 index 0000000..9ef30ea --- /dev/null +++ b/deploy/kubernetes/README.md @@ -0,0 +1,91 @@ +# Oktopus Kubernetes + +## Requirements + +Kubernetes 1.28+ + +### Standalone Installation + +Single Node: +* 8 vCPUs +* 8 GB RAM + +# Installation + +## Download Files + +```shell +git clone https://github.com/OktopUSP/oktopus +export DEPLOYMENT_PATH=oktopus/deploy/kubernetes +``` + + +## MongoBD + +```shell +# Mongo DB Operator at mongodb namespace +helm repo add mongodb https://mongodb.github.io/helm-charts + +helm install community-operator mongodb/community-operator --namespace mongodb --create-namespace + +# Mongo DB ReplicaSet +export DEPLOYMENT_PATH=oktopus/deploy/kubernetes + +kubectl apply -f $DEPLOYMENT_PATH/mongodb.yaml -n mongodb + +# Check Installation +kubectl get pods -n mongodb +``` + +## NATS Server + +```shell +# Download the NATS charts +helm repo add nats https://nats-io.github.io/k8s/helm/charts/ + +# Install NATS with Jetstream Enabled +helm install nats nats/nats --set config.jetstream.enabled=true +``` + +## Oktopus + + +Node Ports + +For this deployment, we are not using a load balancer and kubernetes is deployed on-premises so we are using Nodeports to insource the client traffic into cluster. below the ports set on deployment files: + +1. MQTT broker service (mqtt-svc): 30000 +2. Frontend (frontend-svc): 30001 +3. SocketIO: (socketio-svc): 30002 +4. Controller (controller-svc): 30003 +5. WebSocket (ws-svc): 30005 + +Before deploying the files, edit the frontend.yaml file to set the correct enviroment variables: + +```yaml +env: + - name: NEXT_PUBLIC_REST_ENDPOINT + value: ":30003" + - name: NEXT_PUBLIC_WS_ENDPOINT + value: ":30005" +``` + +```shell +kubectl apply -f $DEPLOYMENT_PATH/mqtt.yaml +kubectl apply -f $DEPLOYMENT_PATH/mqtt-adapter.yaml +kubectl apply -f $DEPLOYMENT_PATH/adapter.yaml +kubectl apply -f $DEPLOYMENT_PATH/controller.yaml +kubectl apply -f $DEPLOYMENT_PATH/socketio.yaml +kubectl apply -f $DEPLOYMENT_PATH/frontend.yaml +kubectl apply -f $DEPLOYMENT_PATH/ws.yaml +kubectl apply -f $DEPLOYMENT_PATH/ws-adapter.yaml +``` + +### Checking cluster status: + +```shell + +kubectl get pods +kubectl get svc + +``` \ No newline at end of file diff --git a/deploy/kubernetes/adapter.yaml b/deploy/kubernetes/adapter.yaml new file mode 100644 index 0000000..d2d2d23 --- /dev/null +++ b/deploy/kubernetes/adapter.yaml @@ -0,0 +1,39 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: adapter +spec: + replicas: 1 + selector: + matchLabels: + app: adapter + strategy: + type: Recreate # Specify the Recreate strategy + template: + metadata: + labels: + app: adapter + spec: + containers: + - name: adapter + image: oktopusp/adapter:latest + resources: + requests: + memory: 64Mi + cpu: 0.1 + limits: + memory: 128Mi + cpu: 0.2 + imagePullPolicy: IfNotPresent + env: + - name: NATS_URL + value: "nats://nats:4222" + - name: NATS_NAME + value: "adapter" + - name: NATS_VERIFY_CERTIFICATES + value: "false" + - name: MONGO_URI + value: "mongodb://oktopusp:oktopusp@mongodb-0.mongodb-svc.mongodb.svc.cluster.local:27017,mongodb-1.mongodb-svc.mongodb.svc.cluster.local:27017,mongodb-2.mongodb-svc.mongodb.svc.cluster.local:27017/adapter?replicaSet=mongodb&ssl=false" + - name: CONTROLLER_ID + value: "oktopusController" + diff --git a/deploy/kubernetes/backend.yaml b/deploy/kubernetes/backend.yaml deleted file mode 100644 index 10a45db..0000000 --- a/deploy/kubernetes/backend.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: backend - labels: - app: backend -spec: - replicas: 1 - selector: - matchLabels: - app: backend - template: - metadata: - labels: - app: backend - spec: - containers: - - name: backend - image: backend:latest - ports: - - containerPort: 8080 \ No newline at end of file diff --git a/deploy/kubernetes/controller.yaml b/deploy/kubernetes/controller.yaml new file mode 100644 index 0000000..450317d --- /dev/null +++ b/deploy/kubernetes/controller.yaml @@ -0,0 +1,53 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: controller +spec: + replicas: 1 + selector: + matchLabels: + app: controller + strategy: + type: Recreate + template: + metadata: + labels: + app: controller + spec: + containers: + - name: controller + image: oktopusp/controller:latest + resources: + # requests: + # memory: 64Mi + # cpu: 0.5 + # limits: + # memory: 256Mi + # cpu: 1 + imagePullPolicy: IfNotPresent + env: + - name: NATS_URL + value: "nats://nats:4222" + - name: NATS_NAME + value: "adapter" + - name: NATS_VERIFY_CERTIFICATES + value: "false" + - name: MONGO_URI + value: "mongodb://oktopusp:oktopusp@mongodb-0.mongodb-svc.mongodb.svc.cluster.local:27017,mongodb-1.mongodb-svc.mongodb.svc.cluster.local:27017,mongodb-2.mongodb-svc.mongodb.svc.cluster.local:27017/?replicaSet=mongodb&ssl=false" + - name: REST_API_PORT + value: "8000" +--- +apiVersion: v1 +kind: Service +metadata: + name: controller-svc +spec: + selector: + app: controller + ports: + - protocol: TCP + port: 8000 + targetPort: 8000 + nodePort: 30003 + type: NodePort + diff --git a/deploy/kubernetes/frontend.yaml b/deploy/kubernetes/frontend.yaml new file mode 100644 index 0000000..6731899 --- /dev/null +++ b/deploy/kubernetes/frontend.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend +spec: + replicas: 1 + selector: + matchLabels: + app: frontend + strategy: + type: Recreate # Specify the Recreate strategy + template: + metadata: + labels: + app: frontend + spec: + containers: + - name: frontend + image: oktopusp/frontend:latest + resources: + requests: + memory: 64Mi + cpu: 100m + limits: + memory: 256Mi + cpu: 200m + ports: + - containerPort: 3000 + imagePullPolicy: IfNotPresent + env: + - name: NEXT_PUBLIC_REST_ENDPOINT + value: "192.168.1.130:30003" + - name: NEXT_PUBLIC_WS_ENDPOINT + value: "192.168.1.130:30005" +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend-svc +spec: + selector: + app: frontend + ports: + - protocol: TCP + port: 3000 + targetPort: 3000 + nodePort: 30001 + type: NodePort diff --git a/deploy/kubernetes/haproxy-kubernetes-ingress-cm.yaml b/deploy/kubernetes/haproxy-kubernetes-ingress-cm.yaml new file mode 100644 index 0000000..c4aabd9 --- /dev/null +++ b/deploy/kubernetes/haproxy-kubernetes-ingress-cm.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: haproxy-kubernetes-ingress + namespace: haproxy-controller +data: + syslog-server: "address:stdout, format: raw, facility:daemon" diff --git a/deploy/kubernetes/haproxy-tcp-services-cm.yaml b/deploy/kubernetes/haproxy-tcp-services-cm.yaml new file mode 100644 index 0000000..a4b8f7f --- /dev/null +++ b/deploy/kubernetes/haproxy-tcp-services-cm.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: haproxy-tcp + namespace: default +data: + 1883: # Port where the frontend is going to listen to. + default/mqtt-svc:1883 # Kubernetes service in the format NS/ServiceName:ServicePort diff --git a/deploy/kubernetes/haproxy-tcp-services.yaml b/deploy/kubernetes/haproxy-tcp-services.yaml new file mode 100644 index 0000000..77db1d6 --- /dev/null +++ b/deploy/kubernetes/haproxy-tcp-services.yaml @@ -0,0 +1,8 @@ +controller: + service: + tcpPorts: + - name: mqtt + port: 1883 + targetPort: 1883 + extraArgs: + - --configmap-tcp-services=default/haproxy-tcp diff --git a/deploy/kubernetes/mongodb.yaml b/deploy/kubernetes/mongodb.yaml new file mode 100644 index 0000000..c8aaf12 --- /dev/null +++ b/deploy/kubernetes/mongodb.yaml @@ -0,0 +1,38 @@ +--- +apiVersion: mongodbcommunity.mongodb.com/v1 +kind: MongoDBCommunity +metadata: + name: mongodb +spec: + members: 3 + type: ReplicaSet + version: "6.0.5" + security: + authentication: + modes: ["SCRAM"] + users: + - name: oktopusp + db: admin + passwordSecretRef: # a reference to the secret that will be used to generate the user's password + name: mongo-secret + roles: + - name: clusterAdmin + db: admin + - name: userAdminAnyDatabase + db: admin + - name: readWriteAnyDatabase + db: admin + scramCredentialsSecretName: my-scram + additionalMongodConfig: + storage.wiredTiger.engineConfig.journalCompressor: zlib + +# the user credentials will be generated from this secret +# once the credentials are generated, this secret is no longer required +--- +apiVersion: v1 +kind: Secret +metadata: + name: mongo-secret +type: Opaque +stringData: + password: oktopusp diff --git a/deploy/kubernetes/mqtt-adapter.yaml b/deploy/kubernetes/mqtt-adapter.yaml new file mode 100644 index 0000000..3d7b7b5 --- /dev/null +++ b/deploy/kubernetes/mqtt-adapter.yaml @@ -0,0 +1,44 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mqtt-adapter +spec: + replicas: 1 + selector: + matchLabels: + app: mqtt-adapter + template: + metadata: + labels: + app: mqtt-adapter + spec: + containers: + - name: mqtt-adapter + image: oktopusp/mqtt-adapter:latest + resources: + requests: + memory: 64Mi + cpu: 0.1 + limits: + memory: 128Mi + cpu: 0.2 + imagePullPolicy: IfNotPresent + env: + - name: NATS_URL + value: "nats:4222" + - name: NATS_NAME + value: "mqtt-adapter" + - name: NATS_VERIFY_CERTIFICATES + value: "false" + - name: MQTT_URL + value: "tcp://mqtt:1883" + - name: MQTT_CLIENT_ID + value: "mqtt-adapter" + - name: MQTT_USERNAME + value: "" + - name: MQTT_PASSWORD + value: "" + - name: MQTT_QOS + value: "1" + - name: MQTT_SERVICE_HOST + value: "mqtt" diff --git a/deploy/kubernetes/mqtt.yaml b/deploy/kubernetes/mqtt.yaml new file mode 100644 index 0000000..0d705ee --- /dev/null +++ b/deploy/kubernetes/mqtt.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: Service +metadata: + name: mqtt-svc +spec: + selector: + app: mqtt + ports: + - protocol: TCP + port: 1883 + targetPort: 1883 + nodePort: 30000 + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mqtt +spec: + replicas: 1 + selector: + matchLabels: + app: mqtt + template: + metadata: + labels: + app: mqtt + spec: + containers: + - name: mqtt + image: rogersacchelli/mqtt:latest + ports: + - containerPort: 1883 + resources: + requests: + memory: 64Mi + cpu: 100m + limits: + memory: 256Mi + cpu: 200m + imagePullPolicy: IfNotPresent + env: + - name: MQTT_PORT + value: ":1883" + - name: MQTT_TLS + value: "false" + - name: LOG_LEVEL + value: "0" # 0 - DEBUG diff --git a/deploy/kubernetes/socketio.yaml b/deploy/kubernetes/socketio.yaml new file mode 100644 index 0000000..a51c5fd --- /dev/null +++ b/deploy/kubernetes/socketio.yaml @@ -0,0 +1,35 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: socketio +spec: + replicas: 1 + selector: + matchLabels: + app: socketio + template: + metadata: + labels: + app: socketio + spec: + containers: + - name: socketio + image: oktopusp/socketio:latest + imagePullPolicy: IfNotPresent + env: + - name: NATS_URL + value: "nats:4222" +--- +apiVersion: v1 +kind: Service +metadata: + name: socketio-svc +spec: + selector: + app: socketio + ports: + - protocol: TCP + port: 5000 + targetPort: 5000 + nodePort: 30002 + type: NodePort diff --git a/deploy/kubernetes/ws-adapter.yaml b/deploy/kubernetes/ws-adapter.yaml new file mode 100644 index 0000000..3be4722 --- /dev/null +++ b/deploy/kubernetes/ws-adapter.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ws-adapter +spec: + replicas: 1 + selector: + matchLabels: + app: ws-adapter + template: + metadata: + labels: + app: ws-adapter + spec: + containers: + - name: ws-adapter + image: oktopusp/ws-adapter:latest + resources: + #requests: + # memory: 64Mi + # cpu: 0.1 + #limits: + # memory: 256Mi + # cpu: 0.2 + imagePullPolicy: IfNotPresent + env: + - name: NATS_URL + value: "nats://nats:4222" + - name: NATS_NAME + value: "ws-adapter" + - name: NATS_VERIFY_CERTIFICATES + value: "0" # 0 - DEBUG + - name: WS_TOKEN + value: "" + - name: WS_AUTH_ENABLE + value: "false" + - name: WS_ADDR + value: "ws-svc" + - name: WS_PORT + value: ":8080" + - name: WS_ROUTE + value: "/ws/controller" + - name: WS_TLS_ENABLE + value: "false" + - name: WS_SKIP_TLS_VERIFY + value: "false" diff --git a/deploy/kubernetes/ws.yaml b/deploy/kubernetes/ws.yaml new file mode 100644 index 0000000..f53f334 --- /dev/null +++ b/deploy/kubernetes/ws.yaml @@ -0,0 +1,52 @@ +apiVersion: v1 +kind: Service +metadata: + name: ws-svc +spec: + selector: + app: ws + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 + nodePort: 30005 + type: NodePort +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ws +spec: + replicas: 1 + selector: + matchLabels: + app: ws + template: + metadata: + labels: + app: ws + spec: + containers: + - name: ws + image: oktopusp/ws:latest + ports: + - containerPort: 8080 + resources: + requests: + memory: 64Mi + cpu: 100m + limits: + memory: 256Mi + cpu: 200m + imagePullPolicy: IfNotPresent + env: + - name: SERVER_PORT + value: ":8080" + - name: SERVER_AUTH_TOKEN + value: "" + - name: SERVER_AUTH_ENABLE + value: "false" + - name: CONTROLLER_EID + value: "oktopusController" + - name: SERVER_TLS_ENABLE + value: "false" diff --git a/frontend/.env b/frontend/.env index 32e4aa9..141984e 100644 --- a/frontend/.env +++ b/frontend/.env @@ -1,17 +1,17 @@ # ----------------------------- Local Environment ---------------------------- # -NEXT_PUBLIC_REST_ENPOINT="http://localhost:8000/api" -NEXT_PUBLIC_WS_ENPOINT="http://localhost:5000/" +NEXT_PUBLIC_REST_ENDPOINT="http://localhost:8000/api" +NEXT_PUBLIC_WS_ENDPOINT="http://localhost:5000/" # ---------------------------------------------------------------------------- # # -------------------------- Production Environment -------------------------- # -#NEXT_PUBLIC_REST_ENPOINT="https://demo.oktopus.app.br/api" -#NEXT_PUBLIC_WS_ENPOINT="https://demo.oktopus.app.br/" +#NEXT_PUBLIC_REST_ENDPOINT="https://demo.oktopus.app.br/api" +#NEXT_PUBLIC_WS_ENDPOINT="https://demo.oktopus.app.br/" # ---------------------------------------------------------------------------- # # ---------------------------- Mocked Environment ---------------------------- # -#NEXT_PUBLIC_REST_ENPOINT="https://d9962fd9-2464-4a30-9a86-a15a04b57ad0.mock.pstmn.io" +#NEXT_PUBLIC_REST_ENDPOINT="https://d9962fd9-2464-4a30-9a86-a15a04b57ad0.mock.pstmn.io" # ---------------------------------------------------------------------------- # diff --git a/frontend/build/Dockerfile b/frontend/build/Dockerfile index 5c9d862..a5d60f8 100644 --- a/frontend/build/Dockerfile +++ b/frontend/build/Dockerfile @@ -2,11 +2,11 @@ FROM node:16.20.2-alpine as builder WORKDIR /app -COPY ../ . +COPY ../ ./ RUN npm install -RUN NEXT_PUBLIC_REST_ENPOINT=REST_API_URL NEXT_PUBLIC_WS_ENPOINT=WS_URL npm run build +RUN NEXT_PUBLIC_REST_ENDPOINT=REST_API_URL NEXT_PUBLIC_WS_ENDPOINT=WS_URL npm run build RUN ls -la && echo "Listing directory contents done" @@ -26,4 +26,4 @@ RUN chmod 755 entrypoint.sh ENTRYPOINT ["/app/entrypoint.sh"] -CMD [ "npm", "run", "start" ] \ No newline at end of file +CMD [ "npm", "run", "start" ] diff --git a/frontend/build/entrypoint.sh b/frontend/build/entrypoint.sh index f4abca7..bf43c58 100644 --- a/frontend/build/entrypoint.sh +++ b/frontend/build/entrypoint.sh @@ -3,16 +3,16 @@ set -Ex function apply_path { - echo "Check that we have NEXT_PUBLIC_REST_ENPOINT vars" - test -n "$NEXT_PUBLIC_REST_ENPOINT" + echo "Check that we have NEXT_PUBLIC_REST_ENDPOINT vars" + test -n "$NEXT_PUBLIC_REST_ENDPOINT" - echo "Check that we have NEXT_PUBLIC_WS_ENPOINT vars" - test -n "$NEXT_PUBLIC_WS_ENPOINT" + echo "Check that we have NEXT_PUBLIC_WS_ENDPOINT vars" + test -n "$NEXT_PUBLIC_WS_ENDPOINT" - find /app/.next \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i "s#REST_API_URL#$NEXT_PUBLIC_REST_ENPOINT#g" - find /app/.next \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i "s#WS_URL#$NEXT_PUBLIC_WS_ENPOINT#g" + find /app/.next \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i "s#REST_API_URL#$NEXT_PUBLIC_REST_ENDPOINT#g" + find /app/.next \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i "s#WS_URL#$NEXT_PUBLIC_WS_ENDPOINT#g" } apply_path echo "Starting Nextjs" -exec "$@" \ No newline at end of file +exec "$@"