diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..6554e1f --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,26 @@ +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/2.0/configuration-reference +version: 2.1 + +# Define a job to be invoked later in a workflow. +# See: https://circleci.com/docs/2.0/configuration-reference/#jobs +jobs: + say-hello: + # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor + docker: + - image: cimg/base:stable + # Add steps to the job + # See: https://circleci.com/docs/2.0/configuration-reference/#steps + steps: + - checkout + - run: + name: "Say hello" + command: "echo Hello, World!" + +# Invoke jobs via workflows +# See: https://circleci.com/docs/2.0/configuration-reference/#workflows +workflows: + say-hello-workflow: + jobs: + - say-hello diff --git a/.dockerignore b/.dockerignore index be2067e..601945f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,3 +5,4 @@ Dockerfile .git README.md .gitignore +.env diff --git a/.gitignore b/.gitignore index ebfe439..1b11676 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,6 @@ typings/ #DynamoDB Local files .dynamodb/ + +# password +secret.yaml diff --git a/app.js b/app.js index 703039c..f971dd1 100644 --- a/app.js +++ b/app.js @@ -5,7 +5,7 @@ const db = require('./db'); const sharks = require('./routes/sharks'); const path = __dirname + '/views/'; -const port = 8080; +const port = process.env.PORT || 8080; app.engine('html', require('ejs').renderFile); app.set('view engine', 'html'); @@ -14,5 +14,5 @@ app.use(express.static(path)); app.use('/sharks', sharks); app.listen(port, function () { - console.log('Example app listening on port 8080!') + console.log('Example app listening on port ${port}!') }) diff --git a/db-deployment.yaml b/db-deployment.yaml new file mode 100644 index 0000000..814ad96 --- /dev/null +++ b/db-deployment.yaml @@ -0,0 +1,54 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.18.0 (06a2e56) + creationTimestamp: null + labels: + io.kompose.service: db + name: db +spec: + replicas: 1 + strategy: + type: Recreate + template: + metadata: + creationTimestamp: null + labels: + io.kompose.service: db + spec: + containers: + - env: + - name: MONGO_DB + valueFrom: + configMapKeyRef: + key: MONGO_DB + name: db-env + - name: MONGO_INITDB_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: mongo-secret + key: MONGO_PASSWORD + - name: MONGO_INITDB_ROOT_USERNAME + valueFrom: + secretKeyRef: + name: mongo-secret + key: MONGO_USERNAME + - name: MONGO_PORT + valueFrom: + configMapKeyRef: + key: MONGO_PORT + name: db-env + image: mongo:4.1.8-xenial + name: db + resources: {} + volumeMounts: + - mountPath: /data/db + name: dbdata + restartPolicy: Always + volumes: + - name: dbdata + persistentVolumeClaim: + claimName: dbdata +status: {} diff --git a/db-env-configmap.yaml b/db-env-configmap.yaml new file mode 100644 index 0000000..2156eb5 --- /dev/null +++ b/db-env-configmap.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +data: + MONGO_DB: sharkinfo + MONGO_PORT: "27017" +kind: ConfigMap +metadata: + creationTimestamp: null + labels: + io.kompose.service: db-env + name: db-env diff --git a/db-service.yaml b/db-service.yaml new file mode 100644 index 0000000..cc4101e --- /dev/null +++ b/db-service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.18.0 (06a2e56) + creationTimestamp: null + labels: + io.kompose.service: db + name: db +spec: + ports: + - port: 27017 + targetPort: 27017 + selector: + io.kompose.service: db +status: + loadBalancer: {} diff --git a/db.js b/db.js index c1d5684..d2a592e 100644 --- a/db.js +++ b/db.js @@ -1,11 +1,25 @@ const mongoose = require('mongoose'); -const MONGO_USERNAME = 'sammy'; -const MONGO_PASSWORD = 'password'; -const MONGO_HOSTNAME = '127.0.0.1'; -const MONGO_PORT = '27017'; -const MONGO_DB = 'sharkinfo'; +const { + MONGO_USERNAME, + MONGO_PASSWORD, + MONGO_HOSTNAME, + MONGO_PORT, + MONGO_DB +} = process.env; + +const options = { + useNewUrlParser: true, + reconnectTries: Number.MAX_VALUE, + reconnectInterval: 500, + connectTimeoutMS: 10000, +}; const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`; -mongoose.connect(url, {useNewUrlParser: true}); +mongoose.connect(url, options).then( function() { + console.log('MongoDB is connected'); +}) + .catch( function(err) { + console.log(err); +}); diff --git a/dbdata-persistentvolumeclaim.yaml b/dbdata-persistentvolumeclaim.yaml new file mode 100644 index 0000000..3241eb0 --- /dev/null +++ b/dbdata-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + creationTimestamp: null + labels: + io.kompose.service: dbdata + name: dbdata +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a391044 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +version: '3' + +services: + nodejs: + image: virgoinvincible/node-kubernetes + container_name: nodejs + restart: always + env_file: .env + environment: + - MONGO_USERNAME=$MONGO_USERNAME + - MONGO_PASSWORD=$MONGO_PASSWORD + - MONGO_HOSTNAME=db + - MONGO_PORT=$MONGO_PORT + - MONGO_DB=$MONGO_DB + ports: + - "80:8080" + volumes: + - .:/home/node/app + - node_modules:/home/node/app/node_modules + networks: + - app-network + command: ./wait-for.sh db:27017 -- /home/node/app/node_modules/.bin/nodemon app.js + + db: + image: mongo:4.1.8-xenial + container_name: db + restart: always + env_file: .env + environment: + - MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME + - MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD + volumes: + - dbdata:/data/db + networks: + - app-network + +networks: + app-network: + driver: bridge + +volumes: + dbdata: diff --git a/docker-upload.sh b/docker-upload.sh new file mode 100755 index 0000000..e3918d6 --- /dev/null +++ b/docker-upload.sh @@ -0,0 +1,22 @@ +# USING BASH SCRIPT TO TAG AND UPLOAD AN IMAGE TO DOCKER HUB + +#!/usr/bin/env bash + +# Assumes that an image is built via `run_docker-compose.sh` + +# Step 1: +# Create dockerpath +dockerpath=nodejs + +# Step 2: +# Authenticate & tag +echo "Docker ID and Image: $dockerpath" +docker login -u virgoinvincible + +#Step 3: +# Tag the images with your Docker ID +docker tag $dockerpath:latest virgoinvincible/$dockerpath + +# Step 4: +# Push image to a docker repository +docker push virgoinvincible/$dockerpath diff --git a/hadolint.sh b/hadolint.sh new file mode 100755 index 0000000..187c18f --- /dev/null +++ b/hadolint.sh @@ -0,0 +1,11 @@ +# USING BASH SCRIPT TO INSTALL HADOLINT + +# Hadolint automates the detection of Dockerfile issues. +#This helps your Docker images adhere to best practices and organizational standards. + +#!/usr/bin/env bash + +# Installing Hadolint +sudo wget -O /bin/hadolint https://github.com/hadolint/hadolint/releases/download/v2.10.0/hadolint-Linux-x86_64 + +sudo chmod +x /bin/hadolint diff --git a/kompose.sh b/kompose.sh new file mode 100755 index 0000000..af0d010 --- /dev/null +++ b/kompose.sh @@ -0,0 +1,15 @@ +# Script on steps to install kubernetes kompose + +#!/usr/bin/env bash + +#installing binary file from a git hub repo +curl -L https://github.com/kubernetes/kompose/releases/download/v1.18.0/kompose-linux-amd64 -o kompose + +#making binary executable +chmod +x kompose + +#moving to PATH +sudo mv ./kompose /usr/local/bin/kompose + +#verify installation +kompose version diff --git a/kubectl-install.sh b/kubectl-install.sh new file mode 100755 index 0000000..77958ff --- /dev/null +++ b/kubectl-install.sh @@ -0,0 +1,30 @@ +# INSTALL KUBECTL BINARY WITH CURL ON LINUX + +#!/usr/bin/env bash + +# Step1: +# Download the latest release with the command +curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + +# Step 2: +# Download the kubectl checksum file +curl -LO "https://dl.k8s.io/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl.sha256" + +# Step 3: +# Validate the kubectl binary against the checksum file +echo "$(cat kubectl.sha256) kubectl" | sha256sum --check + +# Step 4: +# Install kubectl +sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + +# Step 5: +# Install kubectl to the ~/.local/bin director +chmod +x kubectl +mkdir -p ~/.local/bin +mv ./kubectl ~/.local/bin/kubectl +# and then append (or prepend) ~/.local/bin to $PATH + +# Step 6: +# Test to ensure the version you installed is up-to-date +kubectl version --client --output=yaml diff --git a/kubectl.sha256 b/kubectl.sha256 new file mode 100644 index 0000000..42a3c81 --- /dev/null +++ b/kubectl.sha256 @@ -0,0 +1 @@ +fcf86d21fb1a49b012bce7845cf00081d2dd7a59f424b28621799deceb5227b3 \ No newline at end of file diff --git a/minikube-install.sh b/minikube-install.sh new file mode 100755 index 0000000..a91ac84 --- /dev/null +++ b/minikube-install.sh @@ -0,0 +1,22 @@ +# USING BASH SCRIPT TO INSTALL AND START A KUBERNETES CLUSTER + +#!/usr/bin/env bash + +# step 1: +# Installing minikube +curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 +sudo install minikube-linux-amd64 /usr/local/bin/minikube + +# Step 2: +# Test the installation +minikube version + +# Step 3: +# Start the kubernetes cluster +# minikube start +sudo minikube start --force + +# Step 4: +# List kubernetes pods +# minikube kubectl -- get pods -A +sudo minikube kubectl -- get pods -A diff --git a/minikube-linux-amd64 b/minikube-linux-amd64 new file mode 100644 index 0000000..83c2668 Binary files /dev/null and b/minikube-linux-amd64 differ diff --git a/node-modules-persistentvolumeclaim.yaml b/node-modules-persistentvolumeclaim.yaml new file mode 100644 index 0000000..464960d --- /dev/null +++ b/node-modules-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + creationTimestamp: null + labels: + io.kompose.service: node-modules + name: node-modules +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/nodejs-claim0-persistentvolumeclaim.yaml b/nodejs-claim0-persistentvolumeclaim.yaml new file mode 100644 index 0000000..266ce08 --- /dev/null +++ b/nodejs-claim0-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + creationTimestamp: null + labels: + io.kompose.service: nodejs-claim0 + name: nodejs-claim0 +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/nodejs-deployment.yaml b/nodejs-deployment.yaml new file mode 100644 index 0000000..752e8a5 --- /dev/null +++ b/nodejs-deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.18.0 (06a2e56) + creationTimestamp: null + labels: + io.kompose.service: nodejs + name: nodejs +spec: + replicas: 1 + strategy: + type: Recreate + template: + metadata: + creationTimestamp: null + labels: + io.kompose.service: nodejs + spec: + containers: + - args: + - ./wait-for.sh + - db:27017 + - -- + - /home/node/app/node_modules/.bin/nodemon + - app.js + env: + - name: MONGO_DB + valueFrom: + configMapKeyRef: + key: MONGO_DB + name: nodejs-env + - name: MONGO_HOSTNAME + value: db + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: mongo-secret + key: MONGO_PASSWORD + - name: MONGO_PORT + valueFrom: + configMapKeyRef: + key: MONGO_PORT + name: nodejs-env + - name: MONGO_USERNAME + valueFrom: + secretKeyRef: + name: mongo-secret + key: MONGO_USERNAME + image: virgoinvincible/node-kubernetes + name: nodejs + ports: + - containerPort: 8080 + resources: {} + initContainers: + - name: init-db + image: busybox + command: ['sh', '-c', 'until nc -z db:27017; do echo waiting for db; sleep 2; done;'] + restartPolicy: Always + volumes: + - name: nodejs-claim0 + persistentVolumeClaim: + claimName: nodejs-claim0 + - name: node-modules + persistentVolumeClaim: + claimName: node-modules +status: {} diff --git a/nodejs-env-configmap.yaml b/nodejs-env-configmap.yaml new file mode 100644 index 0000000..2cc13f5 --- /dev/null +++ b/nodejs-env-configmap.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +data: + MONGO_DB: sharkinfo + MONGO_PORT: "27017" +kind: ConfigMap +metadata: + creationTimestamp: null + labels: + io.kompose.service: nodejs-env + name: nodejs-env diff --git a/nodejs-service.yaml b/nodejs-service.yaml new file mode 100644 index 0000000..ef082d3 --- /dev/null +++ b/nodejs-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.18.0 (06a2e56) + creationTimestamp: null + labels: + io.kompose.service: nodejs + name: nodejs +spec: + ports: + - name: "80" + port: 80 + targetPort: 8080 + selector: + io.kompose.service: nodejs +status: + loadBalancer: {} diff --git a/package.json b/package.json index 3d0f59d..a3754a2 100644 --- a/package.json +++ b/package.json @@ -18,5 +18,8 @@ "ejs": "^2.6.1", "express": "^4.16.4", "mongoose": "^5.4.10" - } + }, + "devDependencies": { + "nodemon": "^1.18.10" + } } diff --git a/run_kubernetes.sh b/run_kubernetes.sh new file mode 100644 index 0000000..ec7f845 --- /dev/null +++ b/run_kubernetes.sh @@ -0,0 +1,24 @@ +# USING BASH SCRIPT TO START A KUBERNETES DEPLOYMENT +# NOTE:: THIS SCRIPT REQUIRES TO BE ECXECUTED TWICE IN AN INTERVAL OF APPROXIMATELY 3 MINUTES + +#!/usr/bin/env bash + +# This tags and uploads an image to Docker Hub + +# Step 1: +# This is your Docker ID/path +dockerpath=virgoinvincible/nodejs + +# Step 2 +# Run the Docker Hub container with kubernetes +kubectl run nodejs \ + --image=$dockerpath \ + --port=80 + +# Step 3: +# List kubernetes pods +kubectl get pods + +# Step 4: +# Forward the container port to a host +kubectl port-forward nodejs 8000:80 diff --git a/wait-for.sh b/wait-for.sh new file mode 100755 index 0000000..63243fc --- /dev/null +++ b/wait-for.sh @@ -0,0 +1,81 @@ +#!/bin/sh + +# original script: https://github.com/eficode/wait-for/blob/master/wait-for + +TIMEOUT=15 +QUIET=0 + +echoerr() { + if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi +} + +usage() { + exitcode="$1" + cat << USAGE >&2 +Usage: + $cmdname host:port [-t timeout] [-- command args] + -q | --quiet Do not output any status messages + -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit "$exitcode" +} + +wait_for() { + for i in `seq $TIMEOUT` ; do + nc -z "$HOST" "$PORT" > /dev/null 2>&1 + + result=$? + if [ $result -eq 0 ] ; then + if [ $# -gt 0 ] ; then + exec "$@" + fi + exit 0 + fi + sleep 1 + done + echo "Operation timed out" >&2 + exit 1 +} + +while [ $# -gt 0 ] +do + case "$1" in + *:* ) + HOST=$(printf "%s\n" "$1"| cut -d : -f 1) + PORT=$(printf "%s\n" "$1"| cut -d : -f 2) + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -t) + TIMEOUT="$2" + if [ "$TIMEOUT" = "" ]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + break + ;; + --help) + usage 0 + ;; + *) + echoerr "Unknown argument: $1" + usage 1 + ;; + esac +done + +if [ "$HOST" = "" -o "$PORT" = "" ]; then + echoerr "Error: you need to provide a host and port to test." + usage 2 +fi + +wait_for "$@"