Unable to get docker swarm mode working with nodejs - node.js

I'm trying to get a basic nodeJs and postgres system up and running but for some reason the node container keeps receiving a SIGTERM signal and shutting down only to be started back up due to the restart policy and then shutdown again. The cycle goes on and on.
What am I missing here? I ran the same code in non-swarm mode and it worked fine, the container was healthy and stayed up. One more thing I did notice during swarm mode is that inspite of asking docker to keep 1 replica, the docker stack services service_name always returns 0/1 replicas
Posting my dockerfile and docker-compose.yml file here
# BASE stage
FROM node:14-alpine as base
ENV NODE_ENV production
WORKDIR /usr/src/app
COPY package.json ./
COPY yarn.lock ./
RUN yarn install --frozen-lockfile --prod
FROM node:14-alpine
ENV NODE_ENV development
ENV VERSION V1
WORKDIR /usr/src/app
RUN apk --no-cache add curl
COPY src src/
# Other copy commands
COPY --from=base /usr/src/app/node_modules /usr/src/app/node_modules
# check every 5s to ensure this service returns HTTP 200
HEALTHCHECK --interval=5s --timeout=3s --start-period=10s --retries=3 \
CMD curl -fs http://localhost/health
ENTRYPOINT [ "node", "src/index.js" ]
version: "3.7"
services:
api:
image: demo/hobby:v1
deploy:
replicas: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 5
window: 120s
rollback_config:
parallelism: 1
delay: 20s
order: start-first
update_config:
parallelism: 1
delay: 1s
failure_action: rollback
order: start-first
env_file:
- ./.env
ports:
- target: 9200
published: 80
mode: host
networks:
- verse
postgres:
image: "postgres:12.3-alpine"
container_name: "test-db-dev"
networks:
- verse
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_USER=${DB_USER}
expose:
- "5432"
ports:
- "5432:5432"
restart: "unless-stopped"
networks:
verse:
driver: overlay
external: false

I assume that your container is being killed every 30 seconds. If this is true, then this is the cause:
The HEALTHCHECK is trying to curl http://localhost/health (defaults to port 80).
Although you expose the app to the host on port 80, the HEALTHCHECK is performed from the container perspective, where no service is listening on that port.
Assuming that your node app is listening on port 9200 and that a GET performed on /health returns status 200, the Dockerfile should be built like this:
[...]
HEALTHCHECK --interval=5s --timeout=3s --start-period=10s --retries=3 \
CMD curl -fs http://localhost:9200/health
[...]

Related

Docker run exit wit code 0 - Node.js & Postgres

I've build a small Node.js app with a Postgres database. I wanted to Dockerize it, and everything worked fine when I was using docker-compose, now I'm trying to put it on AWS EC2, and I'm using docker run, but it doesn't work.
Docker Run command:
docker run -d -p 80:4000 --name appname hubname/appname
the container starts and stops immediatly
I'm fairly new to Docker so I guess I'm missing something.
Please find my Dockerfile:
FROM node:14 as base
WORKDIR /home/node/app
COPY package*.json ./
RUN npm install
COPY . .
FROM base as production
ENV NODE_PATH=./build
RUN npm start
My docker-compose:
version: '3.7'
services:
appname-db:
image: postgres
container_name: appname-db
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- '5432:5432'
volumes:
- appname-db:/var/lib/postgresql/data
ts-node-docker:
build:
context: .
dockerfile: Dockerfile
target: production
volumes:
- ./src:/home/node/app/src
- ./nodemon.json:/home/node/app/nodemon.json
container_name: ts-node-docker
environment:
DB_HOST: ${DB_HOST}
DB_SCHEMA: ${DB_SCHEMA}
DB_USER: ${DB_USER}
DB_PASSWORD: ${DB_PASSWORD}
depends_on:
- appname-db:
condition: service_healthy
expose:
- '4000'
ports:
- '80:4000'
stdin_open: true
command: npm run start
volumes:
appname-db:
When I do:
docker ps -a I see that the container started and exited right after.
I can't find any logs whatsoever it's very frustrating.
Any help/pointer would be really appreciated.
Edit 1 - Some additional information:
When I'm using docker-compose we can see 2 containers:
However this is what I have with docker run:
You should use CMD and not RUN when you execute the npm run start command. CMD runs every time a container is started, while RUN is just executed once, at build time.
This means you start the container, but nothing else is started inside of it. So it exits because there's nothing more to execute. RUN was already executed last time you built the container.
Use RUN for npm install, otherwise it will try every time to reinstall node_modules you already have. But for the start command – do this instead: CMD ["npm", "run", "start"]
In case it could help you I show you my working docker-compose.yml and Dockerfile. Express API with a Postgres DB.
This is tested and works both on an Ubuntu server and on a dev machine (with docker-compose up for both environments). Note that there are two Dockerfiles (dev/prod).
You don't need to add password/user stuff in your docker-compose, you can just include your env_file and Docker/docker-compose sets everything up correctly for you.
version: "3.8"
services:
# D A T A B A S E #
db:
env_file:
- ./.env
image: postgres
container_name: "db"
restart: always
ports:
- "${POSTGRES_PORT}:${POSTGRES_PORT}"
volumes:
- ./db-data/:/var/lib/postgresql/data/
# A P I #
api:
container_name: "api"
env_file:
- ./.env
build:
context: .
dockerfile: "DOCKERFILE.${NODE_ENV}"
ports:
- ${API_PORT}:${API_PORT}
depends_on:
- db
restart: always
volumes:
- /app/node_modules
- .:/usr/src/service
working_dir: /usr/src/service
# A D M I N E R #
adminer:
env_file:
- ./.env
container_name: "adminer"
image: adminer:latest
restart: always
ports:
- ${ADMINER_PORT}:${ADMINER_PORT}
depends_on:
- db
Dockerfile.dev:
FROM node:14.17.3
ENV NODE_ENV=dev
WORKDIR /
COPY ./package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD ["npm", "run", "start"]
Dockerfile.prod is pretty much the same, just change the environment to prod.
I see is that you include the full path from your home directory when copying, try without that. Just copy from the location relative to your Dockerfile at /.

How to solve docker compose cannot find module '/dockerize'

I have a docker-compose setup with three containers - mysql db, serverless app and test (to test the serverless app with mocha). On executing with docker-compose up --build, its seems like the order of execution is messed up and not in correct sequence. Both mysql db and serverless app need to be in working state in order for test to run correctly (depends_on barely works).
Hence I tried using dockerize module to set a timeout and listen to tcp ports on 3306 and 4200 before starting the test container. But I'm getting an error saying Cannot find module '/dockerize'.
Is there anything wrong with the way my docker-compose.yml and Dockerfile are setup? I'm very new to docker so any help would be welcomed.
Dockerfile.yml
FROM node:12
# Create app directory
RUN mkdir -p /app
WORKDIR /app
# Dockerize is needed to sync containers startup
ENV DOCKERIZE_VERSION v0.6.0
RUN wget --no-check-certificate https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
&& tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
&& rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz
# Install app dependencies
COPY package.json /app/
COPY package-lock.json /app/
RUN npm install -g serverless#2.41.2
RUN npm install
# Bundle app source
COPY . /app
docker-compose.yml
version: '3'
services:
mysql-coredb:
image: mysql:5.6
container_name: mysql-coredb
expose:
- "3306"
ports:
- "3306:3306"
serverless-app:
build: .
image: serverless-app
container_name: serverless-app
depends_on:
- mysql-coredb
command: sls offline --stage local --host 0.0.0.0
expose:
- "4200"
ports:
- "4200:4200"
links:
- mysql-coredb
volumes:
- /app/node_modules
- .:/app
test:
image: node:12
working_dir: /app
container_name: test
volumes:
- /app/node_modules
- .:/app
command: dockerize
-wait tcp://serverless-app:4200 -wait tcp://mysql-coredb:3306 -timeout 15s
bash -c "npm test"
depends_on:
- mysql-coredb
- serverless-app
links:
- serverless-app
Your final test container is running a bare node image. This doesn't see or use any of the packages you install in the Dockerfile. You can set that container to also build: .; Compose will run through the build sequence a second time, but since all of the inputs are the same as the main serverless-app container, Docker will use the build cache for everything, the build will run very quickly, and you'll have two names for the same physical image.
You can also safely remove most of the options you have in the Dockerfile. You only need to specify image: with build: if you're planning to push the image to a registry; you don't need to override container_name:; the default command: should come from the Dockerfile CMD; expose: and links: are related to first-generation Docker networking and aren't necessary; overwriting the image code with volumes: results in ignoring the image contents entirely and getting host-specific behavior (just using Node on the host will be much easier than trying to convince Docker to act like a local Node development environment). So I'd trim this down to:
version: '3.8'
services:
mysql-coredb:
image: mysql:5.6
ports:
- "3306:3306"
serverless-app:
build: .
depends_on:
- mysql-coredb
ports:
- "4200:4200"
test:
build: .
command: >-
dockerize
-wait tcp://serverless-app:4200
-wait tcp://mysql-coredb:3306
-timeout 15s
npm test
depends_on:
- mysql-coredb
- serverless-app

Docker-compose builds but app does not serve on localhost

Docker newbie here. Docker-compose file builds without any issues but when I try to run my app on localhost:4200, I get a message - localhost didn't send any data on chrome and the server unexpectedly dropped the connection in safari. I am working on MacOs Catalina. Here is my yml file:
version: '3.0'
services:
my-portal:
build: .
ports:
- "4200:4200"
depends_on:
- backend
backend:
build: ./backend
ports:
- "3000:3000"
environment:
POSTGRES_HOST: host.docker.internal
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: mypwd
depends_on:
-db
db:
image: postgres:9.6-alpine
environment:
POSTGRES_DB: mydb
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: mypwd
POSTGRES_HOST: host.docker.internal
ports:
- 5432:5432
restart: always
volumes:
- ./docker/db/data:/var/lib/postgresql/data
Log for Angular:
/docker-entrypoint.sh: Configuration complete; ready for start up
Log for Node: db connected
Log for Postgres: database system is ready to accept connections
Below are my Angular and Node Docker files:
FROM node:latest AS builder
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build --prod
EXPOSE 4200
# Stage 2
FROM nginx:alpine
COPY --from=builder /app/dist/* /usr/share/nginx/html/
Node:
FROM node:12
WORKDIR /backend
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD [ "node", "server.js" ]
When I created Angular image and ran my app on localhost:4200 it worked fine. Please let me know if I am missing anything.
Your Angular container is built FROM nginx, and you use the default Nginx configuration from the Docker Hub nginx image. That listens on port 80, so that's the port number you need to use in use ports: directive:
services:
quickcoms-portal:
build: .
ports:
- "4200:80" # <-- second port must match nginx image's port
depends_on:
- backend
The EXPOSE directive in the first stage is completely ignored and you can delete it. The FROM nginx line causes docker build to basically completely start over from a new base image, so your final image is stock Nginx plus the files you COPY --from=builder.

No UDP connection to swarm service

I`m try to develop a microsservice with docker swarm. I have a UDP server listen on port 27901.
I have two Cases:
If I run the image locally and publish the ports I can send data from
the localhost to the container.
If I deploy the service to a swarm with same ports published I get a connection refuesed.
In case 2 I dont understand the behaviour because the visualizer service I deploy with the same compose file is accessible.
DOCKERFILE
FROM python:3.6
EXPOSE 27901/udp
RUN mkdir /app
WORKDIR /app
COPY ./code/ /app
DOCKERCOMPOSE
version: "3.7"
services:
data_receiver:
image: data_receiver:latest
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: on-failure
delay: 5s
ports:
- "27901:27901/udp"
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints: [node.role == manager]
Thanks for your time regards
MarLei

Identical Docker images with different containers and ports not accessible

I'm running Docker host on my Windows dev machine and have 2 identifcal images exposing different ports (3000, 3001). Using the following docker-compose I build and run the containers but the container on port 3001 isn't available via localhost or my IP address.
DockerFile
FROM mhart/alpine-node:8
# Create an app directory (in the Docker container)
RUN mkdir -p /testdirectory
WORKDIR /testdirectory
COPY package.json /testdirectory
RUN npm install --loglevel=warn
COPY . /testdirectory
EXPOSE 3000
CMD ["node", "index.js"]
DockerFile
FROM mhart/alpine-node:8
# Create an app directory (in the Docker container)
RUN mkdir -p /test2directory
WORKDIR /test2directory
COPY package.json /test2directory
RUN npm install --loglevel=warn
COPY . /test2directory
EXPOSE 3001
CMD ["node", "index.js"]
Docker-Compose file
version: '3'
services:
testdirectory:
container_name: testdirectory
environment:
- DEBUG=1
- NODE_ENV=production
- NODE_NAME=testdirectory
- NODE_HOST=localhost
- NODE_PORT=3000
- DB_HOST=mongodb://mongo:27017/testdirectory
- DB_PORT=27017
build:
context: ./test-directory
volumes:
- .:/usr/app/
- /usr/app/node_modules
ports:
- "3000:3000"
depends_on:
- mongodb
command: npm start
test2directory:
container_name: test2directory
environment:
- DEBUG=1
- NODE_ENV=production
- NODE_NAME=test2directory
- NODE_HOST=localhost
- NODE_PORT=3001
- DB_HOST=mongodb://mongo:27017/test2directory
- DB_PORT=27017
build:
context: ./test2-directory
volumes:
- .:/usr/app/
- /usr/app/node_modules
ports:
- "3001:3001"
depends_on:
- mongodb
command: npm start
mongodb:
image: mongo:3.4.4
container_name: mongo
ports:
- 27017:27017
volumes:
- /data/db:/data/db
Is there any obvious I'm missing as when I run
docker container port test2directory
it returns
3001/tcp -> 0.0.0.0:3001
Found the problem! Setting the HOST to localhost in the container caused the problem and changing it to 0.0.0.0 got it working.

Resources