I have developed a nodejs REST API, for which i have built a docker image and now deploying it as a pod on my kubernetes cluster.
Dockerfile
FROM mhart/alpine-node:8
WORKDIR /home/appHome/
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "npm", "start" ]
however, i am passing npm start as my container start up command.
but how do i test my node js application with npm test and verify test results?
when i was doing it in my local system i used to run application in backend and used to run
npm test
in another window. how to achieve the same while deploying it on kubernetes cluster! and remove the test part once it is successfull!
below is my script of package.json,
"scripts": {
"test": "mocha ./test/scheduledTaskTest.js",
"start": "nodemon app.js --exec babel-node --presets es2015,stage-2",
"cmd": "set NODE_ENV=devConfig&& npm start"
},
Below are the deployment and job yaml files.
Deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: scheduled-task-test
spec:
replicas: 1
selector:
matchLabels:
app: scheduled-task-test
template:
metadata:
labels:
app: scheduled-task-test
spec: # pod spec
containers:
- name: st-c1
image: 104466/st
imagePullPolicy: Always
env:
- name: NODE_ENV
value: devConfig
- name: st-c2
image: 104466/st
imagePullPolicy: Always
command: [ 'sh','-c','npm test && sleep 3600']'
TestJob.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: scheduled-task-test-job
labels:
purpose: test
spec:
template:
spec:
containers:
- name: st-c1
image: 104466/st
imagePullPolicy: Always
env:
- name: NODE_ENV
value: devConfig
- name: st-c2
image: 104466/st
imagePullPolicy: Always
command: [ 'sh','-c','npm test && sleep 3600']
restartPolicy: Never
Pod status
scheduled-task-test-7d86c87d44-q9zdv 2/2 Running 1 8m 100.96.9.87 ip-172-20-34-139.us-west-2.compute.internal
scheduled-task-test-job-gt9hx 1/2 Error 0 7m 100.96.9.88 ip-172-20-34-139.us-west-2.compute.internal
Successfully executed test case pod log (deployment results)
kubectl logs scheduled-task-test-7d86c87d44-q9zdv -c st-c2
> ScheduledTask@1.0.0 test /home/appHome/ScheduledTask
> mocha ./test/scheduledTaskTest.js
Testing listTask api
✓ List all the Tasks (435ms)
Testing addTask api
✓ Add a new task (438ms)
Testing updateTask api
✓ Update task
Testing delete task api
✓ Delete task (434ms)
4 passing (1s)
Test failed logs, (Executed containers as in job)
kubectl logs scheduled-task-test-job-gt9hx -c st-c2
> ScheduledTask@1.0.0 test /home/appHome/ScheduledTask
> mocha ./test/scheduledTaskTest.js
Testing listTask api
1) List all the Tasks
Testing addTask api
2) Add a new task
Testing updateTask api
3) Update task
Testing delete task api
4) Delete task
0 passing (61ms)
4 failing
1) Testing listTask api
List all the Tasks:
Uncaught TypeError: Cannot read property 'body' of undefined
at Request._callback (test/scheduledTaskTest.js:24:29)
at self.callback (node_modules/request/request.js:186:22)
at Request.onRequestError (node_modules/request/request.js:878:8)
at Socket.socketErrorListener (_http_client.js:387:9)
at emitErrorNT (internal/streams/destroy.js:64:8)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
2) Testing addTask api
Add a new task :
Uncaught TypeError: Cannot read property 'body' of undefined
at Request._callback (test/scheduledTaskTest.js:43:20)
at self.callback (node_modules/request/request.js:186:22)
at Request.onRequestError (node_modules/request/request.js:878:8)
at Socket.socketErrorListener (_http_client.js:387:9)
at emitErrorNT (internal/streams/destroy.js:64:8)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
3) Testing updateTask api
Update task :
Uncaught TypeError: Cannot read property 'body' of undefined
at Request._callback (test/scheduledTaskTest.js:63:20)
at self.callback (node_modules/request/request.js:186:22)
at Request.onRequestError (node_modules/request/request.js:878:8)
at Socket.socketErrorListener (_http_client.js:387:9)
at emitErrorNT (internal/streams/destroy.js:64:8)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
4) Testing delete task api
Delete task :
Uncaught TypeError: Cannot read property 'body' of undefined
at Request._callback (test/scheduledTaskTest.js:83:20)
at self.callback (node_modules/request/request.js:186:22)
at Request.onRequestError (node_modules/request/request.js:878:8)
at Socket.socketErrorListener (_http_client.js:387:9)
at emitErrorNT (internal/streams/destroy.js:64:8)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)
npm ERR! Test failed. See above for more details.
Describe logs of Pod( of containers deployed as job)
kubectl describe pod scheduled-task-test-job-gt9hx
Name: scheduled-task-test-job-gt9hx
Namespace: default
Node: ip-172-20-34-139.us-west-2.compute.internal/172.20.34.139
Start Time: Tue, 19 Jun 2018 16:28:06 +0000
Labels: controller-uid=bf5569e5-73dd-11e8-8ede-02924b27b126
job-name=scheduled-task-test-job
Annotations: kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"Job","namespace":"default","name":"scheduled-task-test-job","uid":"bf5569e5-73dd-11e8-8ede-02924b27b126","...
kubernetes.io/limit-ranger=LimitRanger plugin set: cpu request for container st-c1; cpu request for container st-c2
Status: Running
IP: 100.96.9.88
Created By: Job/scheduled-task-test-job
Controlled By: Job/scheduled-task-test-job
Containers:
st-c1:
Container ID: docker://7fc17e717921020cec074774ccb87956979712e7de55480be6e6bd586b28ce6d
Image: 104466/st
Image ID: docker-pullable://104466/st@sha256:91414cc48e86975041c233329b1814d7c6d2b76bc839a24fa68e99f92750390f
Port: <none>
State: Running
Started: Tue, 19 Jun 2018 16:28:08 +0000
Ready: True
Restart Count: 0
Requests:
cpu: 100m
Environment:
NODE_ENV: devConfig
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-2tvsm (ro)
st-c2:
Container ID: docker://95837799d34e1e14f7718acc1dc745042b94a33f115aab11a03a25ab4a569c18
Image: 104466/st
Image ID: docker-pullable://104466/st@sha256:91414cc48e86975041c233329b1814d7c6d2b76bc839a24fa68e99f92750390f
Port: <none>
Command:
sh
-c
npm test && sleep 3600
State: Terminated
Reason: Error
Exit Code: 1
Started: Tue, 19 Jun 2018 16:28:10 +0000
Finished: Tue, 19 Jun 2018 16:28:12 +0000
Ready: False
Restart Count: 0
Requests:
cpu: 100m
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-2tvsm (ro)
Conditions:
Type Status
Initialized True
Ready False
PodScheduled True
Volumes:
default-token-2tvsm:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-2tvsm
Optional: false
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.alpha.kubernetes.io/notReady:NoExecute for 300s
node.alpha.kubernetes.io/unreachable:NoExecute for 300s
Events: <none>
If you want to use Kubernetes only, then using Jobs would be the easiest way. A job creates one or more pods and ensures that a specified number of them successfully terminate. As pods successfully complete, the job tracks the successful completions. When a specified number of successful completions is reached, the job itself is complete.
Rough plan:
1. Create a Job for your application.
You can use the Deployment of your application as a template. You need to change kind: Job
and add spec.containers.command: ["npm", "test"]
, the last one will replace CMD [ "npm", "start" ]
defined in your Dockerfile. Here is an example:
apiVersion: batch/v1
kind: Job
metadata:
name: npm-test-job
labels:
purpose: test
spec:
template:
spec:
containers:
- name: npm-test-job
image: <your-image>
command: ["npm", "test"]
restartPolicy: Never
2. Run the Job
Run the Job and wait until it is complete:
kubectl create -f npm-test-job
3. Check the status of the Job
Check status of your Job, for example:
kubectl describe jobs kubectl describe jobs | grep "Pods Statuses"
4. Run the Deployment
If test finished successfully, you can start you deployment:
kubectl create -f npm-deployment
Of course, you need to automate this process. Therefore, you need to develop a script implementing this logic.
But my advice here: it is better to use CI tool, such as Jenkins. It integrates easily with Kubernetes and provides a vast amount of functionalities for such cases.
Just specify 'command: [ "npm", "test" ]' in your container part of deployment.yaml will do that.