Getting Started with Docker: Setting Up a Full-Stack Application

Empty road into the Horizon

If you’re a programmer looking to get started with Docker! In this guide, we’ll walk through setting up a project that uses Docker to manage a full-stack application. We’ll use React for the frontend, Ruby on Rails for the backend, MySQL as the database, and Elasticsearch for our search capabilities. Let’s dive in!

Folder Structure

First, we'll set up the folder structure for our project. Here's how it should look:
project-root/
├── frontend/
│   ├── Dockerfile
│   ├── package.json
│   └── src/
├── backend/
│   ├── Dockerfile
│   ├── Gemfile
│   ├── Gemfile.lock
│   └── config/
├── database/
│   └── my.cnf
├── elasticsearch/
│   └── Dockerfile
├── docker-compose.yml
└── README.md

Folder Explanation:

  • frontend/: Contains all files related to the React frontend application.
  • backend/: Contains all files for the Rails API backend.
  • database/: Stores MySQL configuration files.
  • elasticsearch/: Elasticsearch configuration and Dockerfile.
  • docker-compose.yml: Defines the services for the application stack and how they interact.

Don’t stress too much if you’re missing some files initially. You can add them as you go along.

Setting Up Docker Containers

To manage all the different services, we’ll use Docker Compose. Docker Compose helps you define and manage multi-container Docker applications.

Note: Some of these steps might be optional depending on your setup. I’ll let you know when they are.

Step 1: Write Dockerfiles for Each Service

Each service needs its own Dockerfile to describe how it should be built and run. Let’s go over them!

Frontend Dockerfile (React):

# frontend/Dockerfile
FROM node:18
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
CMD ["npm", "start"]
EXPOSE 3000
  • We start with a Node image (Node 18).
  • Set the working directory to /app.
  • Copy package.json and install dependencies.
  • Copy all other files and run the app.

Backend Dockerfile (Rails):

# backend/Dockerfile
FROM ruby:3.1
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
CMD ["rails", "server", "-b", "0.0.0.0"]
EXPOSE 3001
  • Start with the Ruby image (Ruby 3.1).
  • Install Node.js and PostgreSQL client (optional if you’re using PostgreSQL).
  • Set the working directory and install the Ruby gems.

Elasticsearch Dockerfile:

# elasticsearch/Dockerfile
FROM docker.elastic.co/elasticsearch/elasticsearch:8.10.0
  • This one’s pretty simple, just using the official Elasticsearch image.

Step 2: Create docker-compose.yml

The docker-compose.yml file will define all the services, including their dependencies.

version: '3.9'
services:
  frontend:
    build:
      context: ./frontend
    ports:
      - '3000:3000'
    depends_on:
      - backend # Optional: You could start frontend independently, but it might need the backend to be ready.

  backend:
    build:
      context: ./backend
    ports:
      - '3001:3001'
    environment:
      - DATABASE_HOST=database
      - ELASTICSEARCH_HOST=elasticsearch
    depends_on:
      - database
      - elasticsearch

  database:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: myapp
    ports:
      - '3306:3306'
    volumes:
      - db_data:/var/lib/mysql

  elasticsearch:
    build:
      context: ./elasticsearch
    ports:
      - '9200:9200'
    environment:
      discovery.type: single-node

volumes:
  db_data:
  • Optional Note: Some services might not need to be connected initially, depending on what you’re testing. For example, the frontend might run fine without Elasticsearch.

Step 3: Setting Up the Environment

Before running Docker, we need to make sure our environment variables are properly configured. You can create a .env file in the root directory to manage secrets like database passwords or API keys.

.env File Example:

DATABASE_PASSWORD=password
ELASTICSEARCH_HOST=elasticsearch

This part is optional, but keeping sensitive information out of the main codebase is a good habit to get into!

Step 4: Running Docker Compose

Now that we have everything configured, it’s time to run our stack. Simply navigate to the root directory and run:

docker-compose up --build

This command will build and start all the services as defined in the docker-compose.yml file.

If you want to stop everything, use docker-compose down. Easy, right?

Step 5: Access the Services

  • React Frontend: Available at http://localhost:3000
  • Rails Backend API: Available at http://localhost:3001
  • Elasticsearch: Available at http://localhost:9200

And voilà! You should see all your services running. Don’t worry if you run into issues; Docker can be a bit tricky at first. Just take a deep breath and Google any errors you see.

Conclusion

Docker helps simplify the development workflow by making it easy to run all the services you need with a single command. With this setup, you can easily scale and maintain your application, ensuring all components work seamlessly together.

Dockerizing your project not only makes it easier to manage but also helps in deploying your application across different environments with minimal changes.

And hey, don’t worry if you make mistakes! We all do. Docker takes a little getting used to, but once you get the hang of it, you’ll love it. 😊