<p>I have tested the app using minikube locally and it works. When I use the same Doeckerfile with deploymnt.yml, the pod returns to Error state with the below reason</p>

<p>Error: Cannot find module '/usr/src/app/server.js'</p>

<p>Dockerfile:</p>

<pre><code>FROM node:13-alpine
WORKDIR /api
COPY package.json .
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
</code></pre>

<p>Deployment.yml:</p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-app-dep
  labels:
    app: nodejs-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nodejs-app
  template:
    metadata:
      labels:
        app: nodejs-app
    spec:
      serviceAccountName: opp-sa
      imagePullSecrets:
        - name: xxx
      containers:
      - name: nodejs-app
        image: registry.xxxx.net/k8s_app
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3000
</code></pre>

<p>Assuming it could be a problem with "node_modules", I had "ls" on the WORDIR inside the Dockerfile and it does show me "node_modules". Does anyone what else to check to resolve this issue ?</p>

<ul>
<li>Since I can't give you this level of suggestions on a comment I'm writing you a fully working example so you can compare to yours and check if there is something different.</li>
</ul>

<p><strong>Sources:</strong></p>

<ul>
<li>Your Dockerfile:</li>
</ul>

<pre><code>FROM node:13-alpine
WORKDIR /api
COPY package*.json .
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "node", "server.js" ]
</code></pre>

<ul>
<li>Sample <code>package.json</code>:</li>
</ul>

<pre><code>{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "First Last &lt;first.last@example.com&gt;",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  }
}
</code></pre>

<ul>
<li>sample <code>server.js</code>:</li>
</ul>

<pre><code>'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) =&gt; {
  res.send('Hello World');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);
</code></pre>

<ul>
<li>Build image:</li>
</ul>

<pre><code>$ ls
Dockerfile  package.json  server.js

$ docker build -t k8s_app .
...
Successfully built 2dfbfe9f6a2f
Successfully tagged k8s_app:latest

$ docker images k8s_app
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
k8s_app             latest              2dfbfe9f6a2f        4 minutes ago       118MB
</code></pre>

<ul>
<li>Your deployment sample + service for easy access (called <code>nodejs-app.yaml</code>):</li>
</ul>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-app-dep
  labels:
    app: nodejs-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nodejs-app
  template:
    metadata:
      labels:
        app: nodejs-app
    spec:
      containers:
      - name: web-app
        image: k8s_app
        imagePullPolicy: Never
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: web-app-svc
spec:
  type: NodePort
  selector:
    app: nodejs-app
  ports:
    - port: 8080
      targetPort: 8080
</code></pre>

<p><strong>Note:</strong> I'm using the minikube docker registry for this example, that's why <code>imagePullPolicy: Never</code> is set.</p>

<hr>

<ul>
<li>Now I'll deploy it:</li>
</ul>

<pre><code>$ kubectl apply -f nodejs-app.yaml 
deployment.apps/nodejs-app-dep created
service/web-app-svc created
$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
nodejs-app-dep-5d75f54c7d-mfw8x   1/1     Running   0          3s
</code></pre>

<ul>
<li>Whenever you need to troubleshoot inside a pod you can use <code>kubectl exec -it &lt;pod_name&gt; -- /bin/sh</code> (or <code>/bin/bash</code> depending on the base image.)</li>
</ul>

<pre><code>$ kubectl exec -it nodejs-app-dep-5d75f54c7d-mfw8x -- /bin/sh
/api # ls
Dockerfile         node_modules       package-lock.json  package.json       server.js
</code></pre>

<p>The pod is running and the files are in the <code>WORKDIR</code> folder as stated in the <code>Dockerfile</code>.</p>

<ul>
<li>Finally let's test accessing from outside the cluster:</li>
</ul>

<pre><code>$ minikube service list
|-------------|-------------|--------------|-------------------------|
|  NAMESPACE  |    NAME     | TARGET PORT  |           URL           |
|-------------|-------------|--------------|-------------------------|
| default     | web-app-svc |         8080 | http://172.17.0.2:31446 |
|-------------|-------------|--------------|-------------------------|

$ curl -i http://172.17.0.2:31446
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 11
ETag: W/"b-Ck1VqNd45QIvq3AZd8XYQLvEhtA"
Date: Thu, 14 May 2020 18:49:40 GMT
Connection: keep-alive

Hello World$
</code></pre>

<p>The Hello World is being served as desired.</p>

<p>To Summarize:</p>

<ol>
<li>I Build the Docker Image in <code>minikube ssh</code> so it is cached.</li>
<li>Created the manifest containing the deployment pointing to the image, added the service part to allow access externally using Nodeport.</li>
<li><code>NodePort</code> routes all traffic to the Minikube IP in the port assigned to the service (i.e:31446) and deliver to the pods matching the selector listening on port 8080.</li>
</ol>

<hr>

<p><strong>A few pointers for troubleshooting:</strong></p>

<ul>
<li><a href="https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#describe" rel="nofollow noreferrer"><code>kubectl describe</code></a> <code>pod &lt;pod_name&gt;</code>: provides precious information when the pod status is in any kind of error.</li>
<li><code>kubectl exec</code> is great to troubleshoot inside the container as it's running, it's pretty similar to <code>docker run</code> command.</li>
<li>Review your code files to ensure there is no baked path in it.</li>
<li>Try using <code>WORKDIR /usr/src/app</code> instead of <code>/api</code> and see if you get a different result.</li>
<li>Try using a <a href="https://nodejs.org/fr/docs/guides/nodejs-docker-webapp/#dockerignore-file" rel="nofollow noreferrer"><code>.dockerignore</code></a> file with <code>node_modules</code> on it's content.</li>
</ul>

<p>Try out and let me know in the comments if you need further help</p>
