I have already created a docker-compose.yaml
file, Dockerfile
and entrypoint.sh
file. Dockerfile was used to create a ubuntu container. Inside this ubuntu container, I install Node.js
and clone my project repository, then run the project. The project can be run without any problem. But, need to execute below function written in run.js
file.
const users = require("./user");
users();
the console.log()
is inside the user.js
file,
function users() {
console.log("I am the function in user.js")
}
module.exports = users;
docker-compose.yaml :,
version: '3'
services:
node-backend:
build:
context: .
dockerfile: Dockerfile
image: cron-api
container_name: cron-api-cont
ports:
- 3002:3002
entrypoint: /app/entrypoint.sh
Dockerfile :
FROM ubuntu:22.04
# Install necessary dependencies
RUN apt-get update &&
apt-get install -y git curl cron
# Install Node.js
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash -
RUN apt-get install -y nodejs
# Create app working directory
WORKDIR /app
# Copy the entrypoint script into the container
COPY entrypoint.sh /app/entrypoint.sh
# Set executable permissions for the entrypoint script
RUN chmod +x /app/entrypoint.sh
# Expose the app port
EXPOSE 3002
entrypoint.sh :
!/bin/bash
# Set GitHub credentials
GIT_USERNAME="username"
GIT_TOKEN="my_token_private"
BRANCH="main"
# Clone the repository using credentials
git clone -b $BRANCH "https://${GIT_USERNAME}:${GIT_TOKEN}@github.com/username/node-for-docker-test.git" /app/api
# Check if the cloning process is complete
if [ -d "/app/api" ]; then
echo "Cloning completed successfully."
echo "List of directories inside api:"
ls -d /app/api
else
echo "Cloning failed."
fi
# Go to the backend directory
cd /app/api
# Install node modules
npm ci
# Start the server
npm start &
# Schedule the cron job to execute the users() function every 5 minutes
echo "*/1 * * * * node /app/api/run.js" > /tmp/cron_job.txt
echo "Cron job definition created."
# Check if the run.js file exists and print its content
run_js_file="/app/api/run.js"
if [ -f "$run_js_file" ]; then
echo "Found run.js file. Content:"
cat "$run_js_file"
else
echo "run.js file not found."
fi
# Install the cron job from the file
crontab /tmp/cron_job.txt
echo "Cron job installed."
# Start the cron service
service cron start &
echo "Cron service started."
# Keep the container running
tail -f /dev/null
Using the entrypoint.sh, I clone the repo and install node modules. then start the project. I do not want to write another .sh for the cron job. When I write the command inside the /app/
or /app/api/
directory inside container, it runs the users()
function when I execute node /app/api/run.js
manually.
root@6ef26d9188:/app/api# ls
index.js node_modules package-lock.json package.json run.js user.js
root@6ef26d9188:/app/api# pwd
/app/api
root@6ef26d9188:/app/api# node /app/api/run.js
I am the function in user.js
Inside the docker, the cron service runs .After run the container, output of crontab -l
is;
root@6ef26d9188:/# crontab -l
*/1 * * * * node /app/api/run.js
output of service cron status
is;
root@6ef26d918826:/# service cron status
* cron is running
This is the log of the container:
✔ Container cron-api-cont Created 0.1s
Attaching to cron-api-cont
cron-api-cont | Cloning into '/app/api'...
cron-api-cont | Cloning completed successfully.
cron-api-cont | List of directories inside api:
cron-api-cont | /app/api
cron-api-cont |
cron-api-cont | added 90 packages, and audited 91 packages in 3s
cron-api-cont |
cron-api-cont | 11 packages are looking for funding
cron-api-cont | run `npm fund` for details
cron-api-cont |
cron-api-cont | 3 moderate severity vulnerabilities
cron-api-cont |
cron-api-cont | To address all issues (including breaking changes), run:
cron-api-cont | npm audit fix --force
cron-api-cont |
cron-api-cont | Run `npm audit` for details.
cron-api-cont | npm notice
cron-api-cont | npm notice New major version of npm available! 8.19.4 -> 9.7.2
cron-api-cont | npm notice Changelog: <https://github.com/npm/cli/releases/tag/v9.7.2>
cron-api-cont | npm notice Run `npm install -g [email protected]` to update!
cron-api-cont | npm notice
cron-api-cont | Cron job definition created.
cron-api-cont | Found run.js file. Content:
cron-api-cont | const users = require("./user");
cron-api-cont |
cron-api-cont | users();Cron job installed.
cron-api-cont | Cron service started.
cron-api-cont | * Starting periodic command scheduler cron
cron-api-cont | ...done.
cron-api-cont |
cron-api-cont | > [email protected] start
cron-api-cont | > nodemon index.js
cron-api-cont |
cron-api-cont | [nodemon] 2.0.22
cron-api-cont | [nodemon] to restart at any time, enter `rs`
cron-api-cont | [nodemon] watching path(s): *.*
cron-api-cont | [nodemon] watching extensions: js,mjs,json
cron-api-cont | [nodemon] starting `node index.js`
cron-api-cont | server is running on port 3002
Can anyone tell, why it does not print the console log
result on the terminal for every 1 minute?
2
Answers
In your entrypoint.sh, you have this line:
echo "*/1 * * * * node /app/api/run.js" > /tmp/cron_job.txt
The ">" character would reroute the output of the command to the /tmp/cron_job.txt, so the output does not appear on your console. Therefore, it is also not logged to your container log. Notice how you do not use the ">" character on any other echo command, which all show up in the log as you expect.
According to this answer, you want to use the
tee
command, e.g.echo "*/1 * * * * node /app/api/run.js" | tee /tmp/cron_job.txt
Check whether the output is in the /tmp/cron_job.txt file and see if you can log the output of the cronjob to both the console and the file.
Also, small nitpick: Your comment in entrypoint.sh says to run the cronjob every five minutes, when you actually configure it to run every minute.
Normally a Docker container only runs a single process. If you need multiple processes, you need to run multiple containers. This applies to the cron daemon too: since it’s a separate process, it needs its own container. This should be simple to set up in the
docker-compose.yml
:(This is the entire Compose file; you do not need
image:
for things youbuild:
, and you do not normally need to setcontainer_name:
,networks:
, or to manually override theentrypoint:
.)For this to work well, I’d suggest building your application only once in the Dockerfile, rather than repeating it every single time you start the container. Most of what’s in the entrypoint script should move into the Dockerfile. Don’t run
git
inside Docker at all; instead, add thedocker-compose.yml
andDockerfile
to your application’s source repository, and have theDockerfile
build whatever’s currently checked out.Note that there is only one process per container now. We never launch a background process and don’t try to "start services"; this concept doesn’t really exist in a container and the
service
command does not work reliably. We especially do not need to "keep the container alive". One container is the Node application and one is the cron daemon, and the two containers will stay alive on their own so long as their respective processes are running.