{"id":26415204,"url":"https://github.com/mugilan-codes/node-devops-docker-demo","last_synced_at":"2026-04-12T03:35:36.691Z","repository":{"id":105886128,"uuid":"370271816","full_name":"Mugilan-Codes/node-devops-docker-demo","owner":"Mugilan-Codes","description":null,"archived":false,"fork":false,"pushed_at":"2021-06-14T05:54:00.000Z","size":233,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-13T19:46:09.616Z","etag":null,"topics":["devops","docker","docker-compose","dockerfile","droplet","expressjs","mongodb","mongoose","nginx","redis"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Mugilan-Codes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-05-24T07:53:37.000Z","updated_at":"2023-03-09T02:09:55.000Z","dependencies_parsed_at":null,"dependency_job_id":"df71dc80-9f8d-4737-a495-c38892035d8b","html_url":"https://github.com/Mugilan-Codes/node-devops-docker-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Mugilan-Codes/node-devops-docker-demo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mugilan-Codes%2Fnode-devops-docker-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mugilan-Codes%2Fnode-devops-docker-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mugilan-Codes%2Fnode-devops-docker-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mugilan-Codes%2Fnode-devops-docker-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mugilan-Codes","download_url":"https://codeload.github.com/Mugilan-Codes/node-devops-docker-demo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mugilan-Codes%2Fnode-devops-docker-demo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31703501,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-11T21:17:31.016Z","status":"online","status_checked_at":"2026-04-12T02:00:06.763Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["devops","docker","docker-compose","dockerfile","droplet","expressjs","mongodb","mongoose","nginx","redis"],"created_at":"2025-03-18T00:17:51.146Z","updated_at":"2026-04-12T03:35:36.674Z","avatar_url":"https://github.com/Mugilan-Codes.png","language":"JavaScript","readme":"# node-devops-docker-demo\n\n## Practicing Node Devops with Docker\n\n[Devops with Docker and Node.js Youtube Playlist](https://www.youtube.com/playlist?list=PL8VzFQ8k4U1JEu7BLraz8MdKJILJir7oY)\n\n### Resource\n\n- [Nginx and Let’s Encrypt with Docker in Less Than 5 Minutes](https://pentacent.medium.com/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71)\n- [Setup Nginx and Let’s Encrypt with Docker](https://www.thirdrocktechkno.com/blog/setup-nginx-and-lets-encrypt-with-docker/)\n- [Docker compose of nginx, express, letsencrypt SSL get 502 Bad gateway](https://stackoverflow.com/questions/57743088/docker-compose-of-nginx-express-letsencrypt-ssl-get-502-bad-gateway)\n\n### Commands\n\n- Build App Image\n\n  ```sh\n  docker build -t node-devops-docker-demo-image .\n  ```\n\n- Run a Container (port fowarding, bind mount(read-only), and anonymous volume)\n\n  ```sh\n  docker run -v $(pwd):/app:ro -v /app/node_modules -p 3000:4000 --env-file ./.env -d --name node-devops-docker-demo node-devops-docker-demo-image\n  ```\n\n- Access FileSystem\n\n  ```sh\n  docker exec -it node-devops-docker-demo bash\n  ```\n\n- Exit FileSystem\n\n  ```sh\n  exit\n  ```\n\n- Forcefully Remove a container with volume\n\n  ```sh\n  docker rm node-devops-docker-demo -fv\n  ```\n\n- Using Docker Compose\n\n  - Build App\n\n    ```sh\n    docker-compose up -d\n    ```\n  \n  - use this if there is a change in image (Dockerfile)\n\n    ```sh\n    docker-compose up -d --build\n    ```\n\n  - Delete App\n\n    ```sh\n    docker-compose down -v\n    ```\n\n  - Development docker-compose command\n\n    - up\n  \n      ```sh\n      docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d\n\n      # force re-build image for changes\n      docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build\n\n      # re-build image without downing the container and re creating anonymous volumes\n      docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build -V\n\n      # scale the number of instances\n      docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d --scale node-app=2\n      ```\n\n    - down\n\n      ```sh\n      docker-compose -f docker-compose.yml -f docker-compose.dev.yml down -v\n\n      # don't remove volumes\n      docker-compose -f docker-compose.yml -f docker-compose.dev.yml down\n      ```\n\n  - Production docker-compose command\n\n    - up\n  \n      ```sh\n      docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d\n\n      # force re-build image for changes\n      docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build\n      ```\n\n    - down\n\n      ```sh\n      docker-compose -f docker-compose.yml -f docker-compose.prod.yml down -v\n\n      # don't remove volumes\n      docker-compose -f docker-compose.yml -f docker-compose.prod.yml down\n      ```\n\n- Open MongoDB directly\n\n  ```sh\n  docker exec -it node-devops-docker-demo_mongodb_1 mongo -u \"mugil\" -p \"mypassword\"\n  ```\n\n  **note**: Don't pass in `-v` flag to remove the volumes when using databases as it would ultimately remove all volumes, Instead start up the containers and run `docker volume prune` to remove unused volumes.\n\n- Get network details of container\n\n  ```sh\n  docker inspect \u003ccontainer_name\u003e\n  ```\n\n  **note**: you can directly use the service name from docker-compose instead of using the ipAddress(works only for the services created/declared in docker-compose).\n\n- Open Redis CLI\n\n  ```sh\n  docker exec -it node-devops-docker-demo_redis_1 redis-cli\n  ```\n\n  - View Session Keys\n\n    ```sh\n    KEYS *\n    ```\n\n  - Get Session Details\n\n    ```sh\n    GET \u003csession_key\u003e\n    ```\n\n### Steps to Production\n\n- Create Ubuntu Server on Cloud Platforms like **Digital Ocean** (I am using this one), AWS, etc..\n- Create a Droplet\n- Copy the IP Address of the Droplet provided\n- Open a terminal in your computer and SSH into the droplet\n\n  ```sh\n  ssh root@\u003cip_address_of_droplet_here\u003e\n  ```\n\n- Type in `yes` to conntinue connecting\n- Type in your root password that you used while creating the droplet\n- Install docker engine in the droplet\n\n  ```sh\n  curl -fsSL https://get.docker.com -o get-docker.sh\n\n  sh get-docker.sh\n  ```\n\n- Install docker-compose by following instructions in the official documentation for linux\n\n  ```sh\n  sudo curl -L \"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n\n  sudo chmod +x /usr/local/bin/docker-compose\n  ```\n\n- Set Environment Variables\n\n  ```sh\n  export \u003ckey\u003e=\u003cvalue\u003e\n  ```\n\n- Show all Env variables\n\n  ```sh\n  printenv\n  ```\n\n- Instead of individually adding env variables, setup .env file and add the .env variables into it\n\n  ```sh\n  vi .env\n  ```\n\n- Open `.profile` and add this at the bottom\n\n  ```sh\n  vi .profile\n  ```\n\n  ```vim\n  \u003c!-- Removed the lines for brevity --\u003e\n\n  set -o allexport; source /root/.env; set +o allexport \n  ```\n\n- Create a directory and move into it\n\n  ```sh\n  mkdir app\n\n  cd app\n  ```\n\n- Clone the Git repo in this folder and pull whenever there is a change\n\n  ```sh\n  git clone \u003cgit_repo_url\u003e .\n  ```\n\n  **Note**: This works with public repo. If you want to work with private repos, check [Deploy Keys](https://docs.github.com/en/developers/overview/managing-deploy-keys) section or [How to clone your private repository from GitHub to server, Droplet, VDS, etc?](https://dev.to/koddr/quick-how-to-clone-your-private-repository-from-github-to-server-droplet-vds-etc-39jm)\n\n- Run the production docker-compose command\n\n  ```sh\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d\n\n  # do this to see any changes made\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build\n\n  # rebuild only necessary service to avoid checking other containers unneccessarily\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build node-app\n\n  # when you don't want to check for dependencies\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build --no-deps node-app\n\n  # force rebuild containers even when there is no change\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --force-recreate node-app\n\n  # force rebuild containers even when there is no change without dependecies\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --force-recreate --no-deps node-app\n  ```\n\n- Make requests to `http://\u003cip_address_of_the_droplet\u003e/` routes\n\n- Push Images to docker to avoid building images on production server. Create a repo in `dockerhub`\n\n  - Tag the local image with the name of that of the remote image\n  \n    ```sh\n    docker tag \u003clocal_image\u003e \u003cusername/remote_dockerhub_repo_name\u003e    \n    ```\n\n  - Push the tagged image to dockerhub\n\n    ```sh\n    docker push \u003cusername/remote_dockerhub_repo_name\u003e\n    ```\n\n- Build the image on local machine\n\n  ```sh\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml build\n\n  # build only the services that is required (custom image)\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml build node-app\n  ```\n\n- Push the custom build image to dockerhub\n\n  ```sh\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml push\n\n  # push only the services that we want\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml push node-app\n  ```\n\n- Pull the latest images in the production server\n\n  ```sh\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull\n\n  # only specific image\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull node-app\n  ```\n\n- Update the changes in producton server\n\n  ```sh\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d\n\n  # specific rebuild\n  docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps node-app\n  ```\n\n- Use watchtower to automatically look for changes in the remote custom build image (specify the images that needs to be watched at the end)\n\n  ```sh\n  docker run -d --name watchtower -e WATCHTOWER_TRACE=true -e WATCHTOWER_DEBUG=true -e WATCHTOWER_POLL_INTERVAL=50 -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower app_node-app_1\n  ```\n\n  **NOTE**: No need to pull and update changes in production server if watchtower is used\n\n- Activate docker swarm for orchestration. Get IP of the droplet by `ip add` command\n\n  ```sh\n  docker swarm init --advertise-addr \u003cpublic_ip\u003e\n  ```\n\n  - Add more manager nodes, run this command and follow the instructions\n\n    ```sh\n    docker swarm join-token manager\n    ```\n\n  - Add worker node to swarm\n\n    ```sh\n    docker swarm join --token \u003ctoken_provided\u003e \u003cip\u003e:\u003cport\u003e\n    ```\n\n- Deploy\n\n  ```sh\n  docker stack deploy -c docker-compose.yml -c docker-compose.prod.yml myapp\n  ```\n\n  - check how many nodes are running\n\n    ```sh\n    docker node ls\n    ```\n\n  - check how many stacks are there\n\n    ```sh\n    docker stack ls\n    ```\n\n  - list the services in the stack\n\n    ```sh\n    docker stack services myapp\n    ```\n\n  - list all the services across all stacks\n\n    ```sh\n    docker service ls\n    ```\n\n  - list the tasks in the stack\n\n    ```sh\n    docker stack ps myapp\n    ```\n\n#### TODO\n\n- [X] Add SSL Certificate (https)\n\n- [X] Add Domain Name\n\n- [ ] Modify ./init-letsencrypt.sh to use docker swarm and production docker compose\n\n- [ ] Run the modified ./init-letsencrypt.sh on the server for first time to generate fake certificates\n\n- [ ] Everything must be automated\n\n#### Docker Images\n\n- [node](https://hub.docker.com/_/node)\n- [mongo](https://hub.docker.com/_/mongo)\n- [redis](https://hub.docker.com/_/redis)\n- [nginx](https://hub.docker.com/_/nginx)\n\n#### DOCS\n\n- [Express behind proxies](https://expressjs.com/en/guide/behind-proxies.html)\n- [Docker Script for Ubuntu](https://get.docker.com/)\n- [Install Docker Compose](https://docs.docker.com/compose/install/)\n- [Watchtower](https://containrrr.dev/watchtower/)\n- [Docker Compose Deploy Reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#deploy)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmugilan-codes%2Fnode-devops-docker-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmugilan-codes%2Fnode-devops-docker-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmugilan-codes%2Fnode-devops-docker-demo/lists"}