Repository: appvia/kev
Pull request #321 (2020-10-21 13:28:46)

Node.js app workflow example
Addresses #320 


Patch:
diff --git a/README.md b/README.md
index be15ef9..e5e11a4 100644
--- a/README.md
+++ b/README.md
@@ -154,7 +154,8 @@ Check our [Roadmap][roadmap] for upcoming planned integrations.
 
 - [How does Kev differ from Kompose?](docs/tutorials/how-kev-differs-from-kompose.md)
 - [Getting started with Kev](docs/tutorials/getting-started-with-kev.md)
-- [Iterate on the app with Kev and Skaffold](docs/tutorials/kev-dev-with-skaffold.md)
+- [Develop the app with Kev and Skaffold](docs/tutorials/kev-dev-with-skaffold.md)
+- [Simple Node.js app development workflow example](docs/tutorials/simple-nodejs-app-workflow.md)
 
   This is an example of how to use _Kev_ to iterate and deploy a [WordPress Docker Compose application](https://docs.docker.com/compose/wordpress/) onto Kubernetes.
 
diff --git a/docs/tutorials/how-kev-differs-from-kompose.md b/docs/tutorials/how-kev-differs-from-kompose.md
index 4f9de77..a4671dc 100644
--- a/docs/tutorials/how-kev-differs-from-kompose.md
+++ b/docs/tutorials/how-kev-differs-from-kompose.md
@@ -1,5 +1,5 @@
 ---
-weight: 12
+weight: 13
 title: How does Kev differ from Kompose?
 ---
 
diff --git a/docs/tutorials/simple-nodejs-app-workflow.md b/docs/tutorials/simple-nodejs-app-workflow.md
new file mode 100644
index 0000000..c3c1f5d
--- /dev/null
+++ b/docs/tutorials/simple-nodejs-app-workflow.md
@@ -0,0 +1,98 @@
+---
+weight: 12
+title: Kev workflow example with a simple Node.js App
+---
+
+# Development workflow example with a simple Node.js app
+
+## Get Kev
+
+* Download [Kev](https://github.com/appvia/kev/releases/latest) & add to the PATH
+
+## Initialise project
+
+> Inside the project directory (`./examples/node-app`) instruct Kev to:
+> * provide a way to adjust Kubernetes specific configuration for 3 distinct environments,
+> * prepare the app for use with [Skaffold](https://skaffold.dev/).
+
+```sh
+kev init -e dev -e staging -e prod --skaffold
+```
+
+You will notice that 3 separate environment specific configuration files have been created:
+
+> Added environment specific override files:
+```
+|- docker-compose.kev.dev.yaml
+|- docker-compose.kev.staging.yaml
+|- docker-compose.kev.prod.yaml
+```
+
+Adjust Kubernetes specific application parameters for each of the components as and when necessary. This is done via Compose [labels](../../docs/reference/config-params.md).
+
+It'll also bootstrap the Skaffold config file (`skaffold.yaml`). If skaffold.yaml previously existed then it'll add additional profiles to it.
+
+## Iterate on the application
+
+### One-off K8s manifests render
+
+Once changes to base & environment specific Compose file(s) have been made
+
+> One-off Kubernetes manifests render:
+```sh
+kev render
+```
+
+This will produce K8s manifests for all environments. See [help](../../docs/cli/kev_render.md) for usage examples.
+
+Inspect produced Kubernetes manifests at default `k8s` directory.
+
+### Watch for Compose changes and auto-rebuild K8s manifests
+
+Run the command below to continously watch for changes made to any of the source / environment Compose files related to your application and automatically rebuild Kubernetes manifests for all environments. See [help](../../docs/cli/kev_dev.md) for usage examples.
+
+> Watch Compose changes and auto render Kubernetes manifests:
+```sh
+kev dev
+```
+
+### Watch for Compose and Application source code changes with Build/Push/Deploy loop enabled
+
+Watch for the changes to your application Compose files, as well as application source code and automatically rebuild the K8s manifests and Build/Push/Deploy the app (via Skaffold dev loop) to any Kubernetes cluster upon detected changes. See [help](../../docs/cli/kev_dev.md) for usage examples.
+
+> Watch Compose and App source code changes, render manifests and build/push/deploy with Skaffold:
+```sh
+kev dev --skaffold
+```
+
+Open the browser at `http://localhost:8080`. You should see `Hello World` displayed on the screen.
+
+
+*NOTE*: The command above will use current kubectl context, and will attempt to deploy your app to `default` namespace. Those can be adjusted with `--kubecontext=<context>` & `--namespace=<ns>` options added to the command above.
+
+*IMPORTANT*: If `--kubecontext` is pointing at remote Kubernetes cluster you need to make sure that you adjust `image` in docker-compose.yaml file so that it points at registry you control and are able to push to. Should that be a private registry then make sure that the remote Kubernetes cluster is able to [pull images from it](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/).
+
+Once the app has been built, pushed and deployed via _Kev's_ Skaffold integration you may inspect that the Node app is running in your cluster:
+
+> List Kubernetes application pods for the Node.js app:
+```sh
+$ kubectl --context docker-desktop -n default get po
+
+NAME                   READY   STATUS    RESTARTS   AGE
+app-69d87ffbc8-pq4bs   1/1     Running   0          9s
+```
+
+Now, try to adjust number of replicas for the app by modifying `kev.workload.replicas` label value to "2". You should observe `dev` loop pick up all the changes and do the hard work of generating K8s manifests, building, pushing and deploying your application automatically.
+
+> List Kubernetes application pods for the Node.js app after change to desired replicas number:
+```sh
+$ kubectl --context docker-desktop -n default get po
+
+NAME                   READY   STATUS        RESTARTS   AGE
+app-85b85cf987-8ngks   1/1     Running       0          14s
+app-85b85cf987-h9l2m   1/1     Running       0          16s
+```
+
+Now try and modify the app source code by changing `res.send('Hello World!');` in `server.js` file to something different e.g. `res.send('FOO BAR!');`. Once changes are saved the application will be automatically rebuilt and redeployed. Visit `http://localhost:8080` and see `FOO BAR` appearing on the screen.
+
+That's it. Issue Ctrl+C to stop the `dev` loop and delete objects deployed to Kubernetes namespace.
diff --git a/examples/node-app/Dockerfile b/examples/node-app/Dockerfile
new file mode 100644
index 0000000..9d91e8b
--- /dev/null
+++ b/examples/node-app/Dockerfile
@@ -0,0 +1,19 @@
+FROM node:12
+
+# Create app directory
+WORKDIR /usr/src/app
+
+# Install app dependencies
+# A wildcard is used to ensure both package.json AND package-lock.json are copied
+# where available (npm@5+)
+COPY package*.json ./
+
+RUN npm install
+# If you are building your code for production
+# RUN npm ci --only=production
+
+# Bundle app source
+COPY . .
+
+EXPOSE 8080
+CMD [ "node", "server.js" ]
diff --git a/examples/node-app/README.md b/examples/node-app/README.md
new file mode 100644
index 0000000..dfe598a
--- /dev/null
+++ b/examples/node-app/README.md
@@ -0,0 +1,3 @@
+# Node.js app example
+
+See [workflow example with a simple Node.js App tutorial](../../docs/tutorials/simple-nodejs-app-workflow.md) for details.
diff --git a/examples/node-app/docker-compose.yaml b/examples/node-app/docker-compose.yaml
new file mode 100644
index 0000000..aeb214c
--- /dev/null
+++ b/examples/node-app/docker-compose.yaml
@@ -0,0 +1,8 @@
+version: '3'
+services:
+  app:
+    image: quay.io/appvia/kev-node-app
+    build:
+      context: .
+    ports:
+      - "8080:8080"
diff --git a/examples/node-app/package.json b/examples/node-app/package.json
new file mode 100644
index 0000000..4a7abcf
--- /dev/null
+++ b/examples/node-app/package.json
@@ -0,0 +1,13 @@
+{
+  "name": "kev-node-app",
+  "version": "1.0.0",
+  "description": "Docker-Compose Node.js app on Kubernetes",
+  "author": "Appvia Ltd <info@appvia.io>",
+  "main": "server.js",
+  "scripts": {
+    "start": "node server.js"
+  },
+  "dependencies": {
+    "express": "^4.16.1"
+  }
+}
diff --git a/examples/node-app/server.js b/examples/node-app/server.js
new file mode 100644
index 0000000..e9bd035
--- /dev/null
+++ b/examples/node-app/server.js
@@ -0,0 +1,16 @@
+'use strict';
+
+const express = require('express');
+
+// Constants
+const PORT = 8080;
+const HOST = '0.0.0.0';
+
+// App
+const app = express();
+app.get('/', (req, res) => {
+  res.send('Hello World!');
+});
+
+app.listen(PORT, HOST);
+console.log(`Running on http://${HOST}:${PORT}`);
diff --git a/pkg/kev/skaffold.go b/pkg/kev/skaffold.go
index fc42068..5371232 100644
--- a/pkg/kev/skaffold.go
+++ b/pkg/kev/skaffold.go
@@ -217,7 +217,7 @@ func (s *SkaffoldManifest) SetProfiles(envs []string) {
 				Build: latest.BuildConfig{
 					BuildType: latest.BuildType{
 						LocalBuild: &latest.LocalBuild{
-							Push: &disabled,
+							Push: &enabled,
 						},
 					},
 					TagPolicy: latest.TagPolicy{


Test patch:
diff --git a/pkg/kev/skaffold_test.go b/pkg/kev/skaffold_test.go
index 3017a82..cf717d6 100644
--- a/pkg/kev/skaffold_test.go
+++ b/pkg/kev/skaffold_test.go
@@ -99,13 +99,13 @@ var _ = Describe("Skaffold", func() {
 			})
 
 			It("generates correct pipeline Build section for each environment", func() {
-				disabled := false
+				enabled := true
 
 				for _, p := range manifest.Profiles {
 					Expect(p.Build).To(Equal(latest.BuildConfig{
 						BuildType: latest.BuildType{
 							LocalBuild: &latest.LocalBuild{
-								Push: &disabled,
+								Push: &enabled,
 							},
 						},
 						TagPolicy: latest.TagPolicy{