DEV Community

Cover image for “From Code to Cloud: Building and Shipping a Simple Node.js App with Docker and GitHub”
okunola babatunde
okunola babatunde

Posted on

“From Code to Cloud: Building and Shipping a Simple Node.js App with Docker and GitHub”

Introduction

In the world of DevOps, the ability to package applications into containers and manage them with version control is a fundamental skill. This guide walks you through creating a minimal Node.js app, containerizing it with Docker, and pushing it to GitHub for collaboration and backup.

By following these steps, you’ll not only learn how to build and run containers but also understand how version control ties into modern cloud workflows. This exercise emphasizes operational excellence, reliability, and performance efficiency — three pillars of cloud-native engineering.

Create Folder

Implementation Guide 1

Create Folder

Instruction Summary

Creates a dedicated working directory for the lab and moves your shell into it.

Why It's Needed

Keeps the app and Dockerfile isolated from other files on the machine so the build context stays clean.

Pillar Connection

Operational Excellence — Setting up a clean workspace before you start.

  • To create a folder named "Container-Lab", run this command "mkdir -p ~\container-lab && cd ~\container-lab" container lab

Create app.js

Implementation Guide 1

Create app.js: Create app.js using touch and write the Node.js console log statement

Instruction Summary

Creates the Node.js source file that the container will run.

Why It's Needed

This is the application code your Dockerfile will package into the image.

Pillar Connection

Performance Efficiency — Shipping the smallest possible app for the container.

  • To create app.js, run this command "touch app.js && echo 'console.log("Hello, DevOps!");' > app.js" Note: The first part of the command, "touch app.js" means to create an app known as app.js app.js While the second part of the command, echo 'console.log("Hello, DevOps!");' > app.js app.js

Implementation Guide 1

Create Dockerfile

Instruction Summary

Writes the build recipe Docker uses to package your app: base image, files to copy in, and the startup command.

Why It's Needed

Without a Dockerfile, Docker has no instructions for turning your source code into a runnable image.

Pillar Connection

Operational Excellence — Reproducible builds defined as code.

  • The two commands are in existence. The first command is to create a Dockerfile which "touch Dockerfile "

dockerfile

while the second command prints into the dockerfile created "echo -e 'FROM node:18-alpine\nCOPY app.js .\nCMD ["node","app.js"]' > Dockerfile"
dockerfile

Implementation Guide

  1. Build Image

Instruction Summary

Reads the Dockerfile and builds a portable, versioned image containing your app and its runtime.

Why It's Needed

The image is the artifact that actually gets shipped and run anywhere Docker is installed.

Pillar Connection

Reliability — A versioned image guarantees the same app runs identically everywhere.

  • In other to Build a Docker image from the Dockerfile in the current directory, run this Command "docker build -t simple-container-lab:1.0 ." dockerimage # Note: Ensure you run your docker engine before running this docker image buiding command "docker build -t simple-container-lab:1.0 ." to avoide error notification on your IDE docker image

Implementation Guide

  1. Run Container

Instruction Summary

Starts a container from the image you just built and removes it automatically when it exits.

Why It's Needed

Confirms the image actually runs your app correctly before you ship it anywhere.

Pillar Connection

Operational Excellence — Verify before you trust a build.

  • To create and start a new container from the specified image, "docker run --rm simple-container-lab:1.0" container

Implementation Guide

1 Initialize Git

Instruction Summary

Creates a local .git directory so version control can start tracking your project.

Why It's Needed

Without a repository, Git has nothing to track changes against.

Pillar Connection

Operational Excellence — Version control is the foundation of every DevOps workflow.
-To nitialize a new Git repository in the current directory, run this command "git init"
git init

Implementation Guide

1 Stage Files

Instruction Summary

Marks the project files as ready to be included in the next commit.

Why It's Needed

Git only commits what has been staged — this moves files from the working directory into the staging area.

Pillar Connection

Operational Excellence — Deliberate, reviewable changesets.

  • To know the files that are not staged, run this command "git status" git status -To stage all changed files for the next commit, run this command "git add ." ** git add **Note: In other to view Staged file, re run this command "git status" status

Implementation Guide

  1. Commit Files

Instruction Summary

Saves the staged files as a permanent, named snapshot in your repository's history.

Why It's Needed

Commits are the checkpoints you can always return to, diff against, or roll back.

Pillar Connection

Reliability — A clear history makes recovery and audits possible.

  • Run *git commit -m 'feat: first container' * to create a new commit with all staged changes and the message after -m. git commit

Implementation Guide

  1. Set GitHub Username

Instruction Summary

Stores your GitHub username in a shell variable.

Why It's Needed

Lets the next command build the correct remote URL without you retyping your username.

Pillar Connection

Operational Excellence — Reusable, less error-prone commands.
-To Set the shell variable GITHUB_USERNAME so later commands can reference it with $GITHUB_USERNAME. Run this command "GITHUB_USERNAME="BAOKONCEPTS"
BAOKONCEPTS

Implementation Guide

  1. Add Remote

Instruction Summary
Links your local repository to a repository on GitHub named "origin".

Why It's Needed
Without a remote, there is nowhere for your local commits to be pushed to.

Pillar Connection
Operational Excellence — Connecting local work to a shared, backed-up remote.

GIT ADD

Implementation Guide

  1. Rename Branch

Instruction Summary

Renames the current branch to "main".

Why It's Needed

Matches the default branch name GitHub expects for new repositories, avoiding a push error.

Pillar Connection

Operational Excellence — Consistent naming conventions across your team.

  • To rename the default branch to main, run this command "git branch -M main" git branch -M main

Implementation Guide

1 Push to GitHub

Instruction Summary

Uploads your commits to the "origin" remote and sets "main" to track it.

Why It's Needed

This is what actually gets your work onto GitHub and sets up future pushes/pulls to sync automatically.

Pillar Connection

Reliability — Your work is now backed up and shareable outside your local machine.

  • To Upload your local commits to the remote repository, run this command "git push -u origin main" git push

Summary

This hands-on lab covered the following stages;

  • Creating a clean project folder.

  • Writing a minimal Node.js app (app.js).

  • Defining a Dockerfile for reproducible builds.

  • Building and running a Docker image.

  • Initializing Git and staging files.

  • Linking to GitHub, renaming the branch, and pushing code.

Together, these steps demonstrate the end-to-end DevOps lifecycle starting from writing code to shipping it in a container and backing it up in a shared repository.

Conclusion

By completing this workflow, you’ve learned how to;

  • Create and run a Node.js app inside a Docker container.

  • Use Dockerfiles to define reproducible builds.

  • Apply Git version control to track and manage changes.

  • Push your project to GitHub for collaboration and reliability.

This exercise demonstrates the core practices of DevOps: automation, reproducibility, and collaboration.

Key takeaways from this hands-on lab;

  • Containers make applications portable and consistent across environments.

  • -Dockerfiles are the blueprint for reproducible builds.

  • Git ensures deliberate, reviewable changes and collaboration.

  • GitHub integration connects local work to a shared, backed-up remote.

Practicing all steps as detailed in this article, builds confidence in cloud-native workflows and prepares you for real-world DevOps tasks.

Top comments (0)