项目作者: eiberham

项目描述 :
:dragon: Dragon ball rest api
高级语言: JavaScript
项目地址: git://github.com/eiberham/dragonball.git
创建时间: 2019-09-05T20:36:31Z
项目社区:https://github.com/eiberham/dragonball

开源协议:MIT License

下载


Dragonball


dragonball









GitHub GitHub code size in bytes GitHub top language GitHub last commit GitHub stars

This is the dragon ball rest api, an idea to provide to anyone, relevant information about the anime.
The application is compound of the following features:


  1. SSL support

  2. Data caching with Redis

  3. Clustering via pm2 package

  4. JWT authentication and routes protection

  5. Fancy OAPI Front-end

As a side note endpoint tests via mocha and supertest packages were added for major robustness.

This is the list of endpoints currently available:


































































VerbResourceDescriptionScope
GET/swaggerSwagger UIPublic
POST/authAuthentication resourcePublic
GET/charactersGet the list of charactersPublic
GET/characters/:nameGet a single characterPublic
POST/charactersCreate a characterProtected
DELETE/characters/:idDelete a characterProtected
PATCH/characters/:idUpdate a characterProtected
GET/sagasGet the list of sagasPublic
GET/sagas/:nameGet a single sagaPublic
POST/sagasCreate a sagaProtected
DELETE/sagas/:idDelete a sagaProtected
GET/filmsGet a list of related filmsPublic
GET/films/:nameGet info about a single filmPublic
POST/filmsCreate a filmProtected
DELETE/films/:idDelete a filmProtected
GET/usersGet a list of usersPublic
GET/users/:nameGet info about a single userPublic
POST/usersCreate userProtected
DELETE/users/:idDelete userProtected

There’s a OAPI resource to test all the endpoints, you have to log yourself in in order to test those endpoints who are protected. This is how the swagger page looks like:


swagger

:rocket: How to run it ?

Before doing anything you should clone the repo:

  1. foo@bar:~$ git clone https://github.com/eiberham/dragonball.git

You should first install docker and docker compose by running:

  1. foo@bar:~$ sudo apt-get install docker.io docker-compose

Then log into your docker hub account by typing:

  1. foo@bar:~$ docker login --username YOUR_USERNAME --password YOUR_PASSWORD

:warning: Important

If for any reason, you come across with the following error while trying to log in (as i did) …

  1. `Error saving credentials: error storing credentials - err: exit status 1, out: `Error calling StartServiceByName for org.freedesktop.secrets: Timeout was reached``

… I could solve that by installing the following packages:

  1. foo@bar:~$ sudo apt install gnupg2 pass

…Or if you face an error like this

  1. ERROR: for db Cannot start service db: driver failed programming external connectivity on endpoint

Just run

  1. foo@bar:~$ service mongodb stop

Finally run compose:

  1. foo@bar:~$ docker-compose up

:anchor: Docker hub

If you wish to push the docker image to your docker hub account simply build the image and push it e.g:

  1. foo@bar:~$ docker build -t username/dragonball:tag .
  2. foo@bar:~$ docker login
  3. foo@bar:~$ docker push username/dragonball:tag

To limit resource usage when running a container :

  1. foo@bar:~$ docker run -d --name dragonball \
  2. --publish 8080:8080
  3. --memory 200m \
  4. --memory-swap 1G \
  5. --cpu-shares 1024 \
  6. username/dragonball:tag

:package: Aws

In order to deploy it to the cloud, for example to an ec2 instance over aws:

First make sure you downloaded the ec2 instance’s key pair to a safe place in your computer.

Then you should give it proper permissions by running:

  1. foo@bar:~$ chmod 400 dragonball.pem

Next step is to delete the node_modules folder directory of your project:

  1. foo@bar:~$ rm -rf node_modules

Next step is to copy your project files:

  1. foo@bar:~$ scp -r -i dragonball.pem ~/dragonball ec2-user@8.32.145.3:~/

Next step is to connect to the EC2 instance via SSH:

  1. foo@bar:~$ ssh -i dragonball.pem ec2-user@8.32.145.3

Then run the commands below once you’re successfully connected to install docker.

  1. sudo yum update
  2. sudo yum install docker
  3. sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-`uname -s`-`uname -m` | sudo tee /usr/local/bin/docker-compose > /dev/null
  4. sudo chmod +x /usr/local/bin/docker-compose
  5. sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

Now start the docker service.

  1. foo@bar:~$ sudo service docker start

Finally run

  1. foo@bar:~$ sudo docker-compose up

Done!

:ship: Kubernetes

This is a guideline for myself for running this api in a kubernetes cluster :stuck_out_tongue:

So alternatively, if you want to run it in a kubernetes cluster in your host machine do the following
(tested on mac os with docker desktop):

If you take a look at the source code you’ll see that the application uses mongodb by means of persistent storage and redis as a cache or volatile storage, normally third party services like these live in their own pods, so we’re going to start defining the most relevant one first and then we’ll follow up with the rest.

From the docs

minikube quickly sets up a local Kubernetes cluster on macOS, Linux, and Windows. We proudly focus on helping application developers and new Kubernetes users.

From the docs

Helm helps you manage Kubernetes applications — Helm Charts help you define, install, and upgrade even the most complex Kubernetes application. Charts are easy to create, version, share, and publish — so start using Helm and stop the copy-and-paste.

Before anything make sure you have installed minikube and helm in your machine and proceed to create a kubernetes cluster:

  1. brew update
  2. curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64
  3. sudo install minikube-darwin-amd64 /usr/local/bin/minikube
  4. brew install helm
  5. minikube start --vm=true

Express

First off we need to conteinerize the application by building a docker image, on the root folder you’ll find a dockerfile. Later on, when creating the deployment objects we will need it.

dockerfile

  1. FROM node:10.16.0
  2. WORKDIR /usr/src/app
  3. COPY package*.json ./
  4. RUN npm install --only=prod
  5. COPY . .
  6. RUN npm install -g nodemon
  7. EXPOSE 3000
  8. CMD npm run dev

In order to build the image get into the application’s root directory, run this command, log into your dockerhub account and push the image

  1. cd dragonball
  2. docker build -t eiberham/dragonball:v1 .
  3. docker login
  4. docker push eiberham/dragonball:v1

Once completed we have to define our express deployment and service objects. For the service we have to define its type as load balancer so that it can redirect traffic to the right pod based on network load.

express.yml

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: express
  5. spec:
  6. selector:
  7. app: express
  8. ports:
  9. - name: "3000"
  10. port: 3000
  11. targetPort: 3000
  12. type: LoadBalancer
  13. ---
  14. apiVersion: apps/v1
  15. kind: Deployment
  16. metadata:
  17. name: express
  18. spec:
  19. replicas: 1
  20. selector:
  21. matchLabels:
  22. app: express
  23. template:
  24. metadata:
  25. labels:
  26. app: express
  27. spec:
  28. containers:
  29. - image: eiberham/dragonball:v1
  30. name: dragonball
  31. ports:
  32. - containerPort: 3000
  33. imagePullPolicy: Always

Now run:

  1. kubectl apply -f express.yml

Ultimately, as we have a service of type:LoadBalancer we’d need to expose the service by using ingress, but before let us enable the ingress add-on in minikube :

  1. minikube addons enable ingress

ingress.yml

  1. apiVersion: networking.k8s.io/v1
  2. kind: Ingress
  3. metadata:
  4. name: entrance
  5. annotations:
  6. nginx.ingress.kubernetes.io/rewrite-target: /$1
  7. spec:
  8. rules:
  9. - host: localhost
  10. http:
  11. paths:
  12. - path: /
  13. pathType: Prefix
  14. backend:
  15. service:
  16. name: express
  17. port:
  18. number: 3000

Now run:

  1. kubectl apply -f ingress.yml

Mongo

The mongo instance will have authentication enabled so we’ll need to provide username and password. Let us create the secrets.yml file that is going to hold our credentials:

secrets.yml

  1. apiVersion: v1
  2. kind: Secret
  3. metadata:
  4. name: mongo-secret
  5. type: Opaque
  6. stringData:
  7. USERNAME: eiberham
  8. PASSWORD: eiberham

Now run:

  1. kubectl apply -f secrets.yml
  2. ```

Since the idea is to we create the bash script that will prepopulate the database, we’re going to create a seeding bash script. For now, the most important thing to have is a user who can authenticate and issue requests to protected routes:

seeding.sh

  1. mongosh "mongodb://127.0.0.1:27017/dragonball" --username $USERNAME -p $PASSWORD --authenticationDatabase dragonball <<'EOF'
  2. db.users.insertOne({
  3. username : 'admin',
  4. password : '$2b$10$al8KvO3PCchoB/nmwU6XZ.HjpmGRSw48SS8U8P0IjRuQlfkJKISUK',
  5. name : 'Admin',
  6. profile : 2.0
  7. })
  8. db.characters.insertOne({
  9. name: 'Goku',
  10. description: 'Goku is the main protagonist of the dragon ball series',
  11. avatar:
  12. 'https://vignette.wikia.nocookie.net/dragonball/images/5/5b/Gokusteppingoutofaspaceship.jpg/revision/latest/scale-to-width-down/224?cb=20150325220848'
  13. })
  14. EOF

In the code above we have defined an insert for the users collection using admin as username and password as well as an insert for the characters collection.

  1. kubectl create configmap seeding-configmap --from-file=seeding.sh

In order to create the deployment/service for the mongo database we will use helm, but beforehand we have to seed the database.

values.yml

  1. mongodb:
  2. auth:
  3. usernames:
  4. - eiberham
  5. passwords:
  6. - eiberham
  7. databases:
  8. - dragonball
  9. initdbScripts:
  10. enabled: true
  11. configMapName: seeding-configmap
  12. extraEnvVars:
  13. - name: USERNAME
  14. valueFrom:
  15. secretkeyRef:
  16. name: mongo-secret
  17. key: username
  18. - name: PASSWORD
  19. valueFrom:
  20. secretkeyRef:
  21. name: mongo-secret
  22. key: password

Now it’s time to install the mongo chart. If you wish to look

  1. noglob helm install mongo oci://registry-1.docker.io/bitnamicharts/mongodb \
  2. --set auth.usernames[0]=$(kubectl get secret mongo-secret -o jsonpath='{.data.USERNAME}' | base64 --decode) \
  3. --set auth.passwords[0]=$(kubectl get secret mongo-secret -o jsonpath='{.data.PASSWORD}' | base64 --decode) \
  4. --set auth.databases[0]=dragonball \
  5. --set initdbScriptsConfigMap=seeding-configmap \
  6. --set extraEnvVarsSecret=mongo-secret \
  7. --values values.yml --debug

If you want to check the underlying manifest for this helm release you can issue the following command:

  1. helm get manifest mongo

You can either check the pod logs to make sure there was no error or log into the pod and query any seeded collection. Plus the seeding script should be located at inside the pod.

  1. kubectl logs <<pod>>
  2. kubectl exec it <<pod>> /bin/bash
  3. mongosh "mongodb://127.0.0.1:27017/dragonball" --username eiberham -p eiberham --authenticationDatabase dragonball
  4. db.characters.find()

Redis

Finally we need a redis instance, so we will install a helm chart with authentication disabled and just one replica:

  1. noglob helm install redis oci://registry-1.docker.io/bitnamicharts/redis \
  2. --set auth.enabled=false \
  3. --set replica.replicaCount=1

If you want to check the underlying manifest for this helm release you can issue the following command:

  1. helm get manifest redis

Now check if pods are running

  1. kubectl get pods

By having every piece of the puzzle in place proceed to issue the following command to get the express url:

  1. minikube service express --url

That should give us the express service’s url and port. Now if you issue a curl to the auth endpoint it should work:

  1. curl -X POST https://192.168.64.30:30136/api/auth -k -d '{ "user":"admin", "password":"admin" }' -H 'Content-Type: application/json'

:cloud: Google cloud

First log in

  1. gcloud auth login

Now set the project where you want to create the kubernetes cluster

  1. gcloud config set project DRAGONBALL_PROJECT_ID

Then create a cluster by running this command:

  1. gcloud container clusters create dragonball \
  2. --num-nodes 2 \
  3. --machine-type n1-standard-2 \
  4. --zone us-central1-a

Get the credentials

  1. gcloud container clusters get-credentials dragonball --zone us-central1-a

Update coming soon …

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

:pushpin: License

This project is licensed under the MIT License - see the LICENSE.md file for details

MADE WITH ❤ BY ABRAHAM