Skip to content
Indus LeveL
docker terraform gcp nodejs mongodb docker-compose devops automation

End-to-End Docker Containerization and Terraform GCP Remote State Setup

A complete engineering guide to installing Docker CE, orchestrating MongoDB and Node.js apps via Docker Compose, managing Makefiles, and configuring Terraform GCS remote state backends.

2 min read
Cover illustration representing Docker containerization, Node.js microservices, MongoDB storage, and Terraform Infrastructure as Code on Google Cloud

When transitioning from traditional virtual machine administration to modern DevOps engineering, mastering containerization and Infrastructure as Code (IaC) is essential. Understanding how to bundle applications into lightweight containers, orchestrate multi-tier services, and manage cloud infrastructure through code forms the backbone of modern reliability engineering.

In this comprehensive guide, I will walk you through a complete end-to-end deployment workflow: installing Docker CE on CentOS 7, orchestrating a MongoDB and Mongo-Express administration stack via custom Docker bridge networks, containerizing a Node.js Express application, streamlining operations with a Makefile, and establishing a secure Terraform remote state backend on Google Cloud Storage (GCS).

Prerequisites

You will need a clean CentOS 7 VM with root privileges, alongside an active Google Cloud Platform (GCP) account to provision storage buckets and Service Account credentials.


Step 1: Base System Update and Docker CE Installation

First, update your system packages, install required development utilities, and disable SELinux to ensure smooth container network bridging.

# Update system and install core utilities
yum update -y
yum install epel-release yum-utils bash-completion net-tools git -y

# Disable SELinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

# Set firewall to trusted mode for container communication
firewall-cmd --set-default=trusted && firewall-cmd --list-all

# Reboot server to bring up clean kernel baseline
reboot

Installing Docker CE and Docker Compose

Once back online, configure the official Docker CE repository and install Docker engines alongside Docker Compose.

# Configure Docker CE repository
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# Install Docker engine and Compose
yum install docker-ce docker-ce-cli containerd.io docker-compose -y

# Enable and start Docker daemon
systemctl start docker
systemctl enable docker
systemctl status docker

Verify your installation by pulling and executing the verification container:

docker run hello-world

Step 2: Orchestrating MongoDB and Mongo-Express via Docker Networks

Multi-tier applications require isolated networking. We will construct a custom bridge network (mongo-network) and deploy a MongoDB database alongside the Mongo-Express web administration interface.

# Check default Docker networks
docker network ls

# Create custom isolated bridge network
docker network create mongo-network

# Verify new network allocation
docker network ls

Deploying the Database Tier

Spin up the MongoDB container attached to our custom network, injecting root administrative credentials via environment variables:

docker run -p 27017:27017 -d \
    -e MONGO_INITDB_ROOT_USERNAME=admin \
    -e MONGO_INITDB_ROOT_PASSWORD=Randompassword \
    --name mongodb \
    --net mongo-network \
    mongo 

Deploying the Web Administration Tier

Similarly, deploy Mongo-Express, linking it directly to the MongoDB instance:

docker run -p 8081:8081 -d \
    -e ME_CONFIG_MONGODB_ADMINUSERNAME=admin \
    -e ME_CONFIG_MONGODB_ADMINPASSWORD=Randompassword \
    -e ME_CONFIG_MONGODB_SERVER=mongodb \
    --net mongo-network \
    --name mongo-express \
    mongo-express

Check the active running status of both containers:

docker ps

Step 3: Application Containerization (Dockerfile and Docker Compose)

To orchestrate the entire application stack seamlessly, we transition from manual CLI execution to declarative orchestration using Docker Compose and a multi-stage Dockerfile.

Installing Node.js and Cloning Application Code

# Install Node.js repository and packages
curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -
yum install -y nodejs

# Clone demo application repository
cd /root
git clone https://gitlab.com/nanuchi/techworld-js-docker-demo-app.git
cd /root/techworld-js-docker-demo-app/app

# Install dependencies
npm install
npm audit fix

Structuring the Dockerfile

Create a Dockerfile in the root of the application repository using a lightweight Alpine Linux base image:

# /root/techworld-js-docker-demo-app/Dockerfile
FROM node:13-alpine

ENV MONGO_DB_USERNAME=admin \
    MONGO_DB_PWD=Randompassword

RUN mkdir -p /home/app
COPY ./app /home/app

WORKDIR /home/app
RUN npm install

CMD ["node", "server.js"]

Build the custom Docker image:

docker build -t my-app:1.0 .
docker images

Structuring docker-compose.yaml

Create the declarative Compose manifest to coordinate the entire multi-container deployment:

# /root/techworld-js-docker-demo-app/docker-compose.yaml
version: '3'
services:
  mongodb:
    image: mongo
    ports:
      - "27017:27017"
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=Randompassword
    volumes:
      - mongo-data:/data/db

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - "8080:8081"
    environment:
      - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
      - ME_CONFIG_MONGODB_ADMINPASSWORD=Randompassword
      - ME_CONFIG_MONGODB_SERVER=mongodb

volumes:
  mongo-data:
    driver: local

Execute the orchestration stack in detached mode:

docker-compose -f docker-compose.yaml up -d

Step 4: Operational Streamlining via Makefile

To prevent team members from needing to memorize lengthy Docker and Compose commands, maintain a standard Makefile.

# /root/techworld-js-docker-demo-app/Makefile
.PHONY: up down restart logs build

up:
	docker-compose -f docker-compose.yaml up -d

down:
	docker-compose -f docker-compose.yaml down

restart: down up

logs:
	docker-compose -f docker-compose.yaml logs -f

build:
	docker build -t my-app:1.0 .

Step 5: Securing Credentials and Establishing Terraform GCP Remote State

When managing infrastructure through Terraform, storing state files locally risks concurrency conflicts and secrets exposure. We establish a secure remote state backend on Google Cloud Storage (GCS).

1. Securing Credentials (.gitignore and .dockerignore)

Generate a GCP Service Account key (terraform-sa-key.json) with Object Storage Admin privileges. Ensure this sensitive key file is strictly ignored in your repository manifests:

# .gitignore
node_modules
config/config.env
*.key.json

# .dockerignore
node_modules
*.key.json

Export the credentials variable to your shell environment:

export GOOGLE_APPLICATION_CREDENTIALS=$PWD/terraform-sa-key.json
echo $GOOGLE_APPLICATION_CREDENTIALS

2. Provisioning the GCP Storage Bucket

Authenticate with Google Cloud and provision a globally unique GCS bucket:

gcloud auth login
gcloud config set project storybooks-338209

# Create GCS bucket for remote state storage
gsutil mb -p storybooks-338209 gs://storybooks-338209-terraform

3. Initializing Terraform Remote State Backend

Construct your Terraform backend configuration (main.tf) referencing the newly provisioned GCS bucket:

# /root/storybooks/terraform/main.tf
terraform {
  backend "gcs" {
    bucket = "storybooks-338209-terraform"
    prefix = "/state/storybooks"
  }
}

Initialize your Terraform environment:

terraform init

Your engineering environment is now fully containerized, orchestrated, operationalized, and backed by robust cloud-native Infrastructure as Code!

References

Back to Blog
Share:

Follow along

Stay in the loop — new articles, thoughts, and updates.