How to Use Docker for Local Development Environments

Cowboy Developer riding a Docker Whale in the Cloud

Docker has revolutionized the way developers create and manage local development environments. Instead of manually setting up software dependencies, configurations, and environment variables on your local machine, Docker lets you spin up containers that replicate your production environment with minimal hassle. In this guide, we’ll explore how to set up a local development environment using Docker, saving you time and ensuring consistency across different machines.


Why Use Docker for Local Development?

Using Docker for local development offers several benefits:

  • Consistency: Docker images are platform-independent, so you can replicate the same environment across different systems. This eliminates the “works on my machine” problem.
  • Isolation: Containers offer isolated environments, keeping dependencies for one project separate from others.
  • Version Control for Environments: Docker lets you specify exact versions of software and dependencies, ensuring compatibility across versions.
  • Quick Spin-up: Start, stop, or reset your development environment in seconds.

To follow along with the complete working code, check out the GitHub repository here.


Step 1: Install Docker

Before getting started, you’ll need to install Docker on your machine. Visit Docker’s official website and follow the installation guide for your operating system. Once Docker is installed, verify by running:

Bash
docker --version

Step 2: Create a Dockerfile

A Dockerfile is a script with instructions on how to build your environment. This file includes base images, dependencies, environment variables, and other configurations. Let’s say you’re working on a Node.js application. Here’s a basic Dockerfile for such an environment:

Dockerfile
# Use an official Node.js image as the base
FROM node:latest

# Set the working directory in the container
WORKDIR /app

# Copy package.json and install dependencies
COPY package.json .
RUN npm install

# Copy the rest of the application code
COPY src/ .

# Expose the application port
EXPOSE 3000

# Run the application
CMD ["npm", "start"]

Save this file in your project directory as Dockerfile.


Step 3: Ignore Certain Files

At times, we may not want certain files or folders to be sent to a Docker container. In our current setup, we’ll exclude the node_modules folder, as these files are specifically built for the host system and not for the container environment. To handle this, let’s create a .dockerignore file.

Plaintext
**/node_modules

This will exclude any node_modules folders found within the project.


Step 4: Build the Docker Image

To create an image from your Dockerfile, run the following command in your terminal:

Bash
docker build -t my-node-app .

This command tells Docker to build an image called my-node-app from the Dockerfile in the current directory (.). The image contains all dependencies and configurations defined in the Dockerfile.


Step 5: Set Up Docker Compose for Multi-Container Applications

If your application requires multiple services (e.g., a web server, database, or cache), Docker Compose simplifies managing these services. For example, let’s add a MySQL database to our Node.js application.

Create a file called docker-compose.yml:

YAML
version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
    depends_on:
      - db

  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: examplepassword
      MYSQL_DATABASE: mydatabase
    ports:
      - "3306:3306"

In this setup:

  • app is the service for our Node.js application. It depends on db to start first.
  • db is the MySQL service that provides a database instance for the application.

Step 6: Start Your Development Environment

To start both containers, use the following command:

Bash
docker-compose up

Docker Compose will build and start both the application and database containers. You can visit your app in the browser at http://localhost:3000, and the MySQL instance is accessible at localhost:3306.

To stop the containers, press Ctrl + C, or run:

Bash
docker-compose down

Step 7: Persist Data with Docker Volumes

During development, it’s common to need data persistence. Docker volumes allow you to save data even if the container is stopped or recreated. In your docker-compose.yml file, you can add volumes like this:

YAML
services:
  app:
    # other settings
    volumes:
      - .:/app

  db:
    # other settings
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

With this configuration, the application code on your host machine is mounted into the container, allowing for code changes without rebuilding. The db_data volume preserves the database data.


Step 8: Use Environment Variables

Environment variables let you configure sensitive information (like passwords and API keys) without hard-coding them into your codebase. Docker Compose lets you define environment variables within the docker-compose.yml file, or you can load them from a .env file for easy management.

1. Create a .env file in your project directory:

Plaintext
MYSQL_ROOT_PASSWORD=examplepassword
MYSQL_DATABASE=mydatabase

2. Modify your docker-compose.yml file:

YAML
environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  MYSQL_DATABASE: ${MYSQL_DATABASE}

Docker will automatically load variables from .env when you run docker-compose up.


Step 9: Debugging with Docker

Docker makes it easy to inspect and debug your containers:

  • Logs: View logs with docker logs <container_name>.
  • Shell Access: Open an interactive shell in a running container with docker exec -it <container_name> bash.
  • Resource Usage: Use docker stats to monitor resource usage across all containers.

These tools are invaluable for debugging issues during development.

To learn more about basic Docker commands, check out my other blog article. Essential Docker Commands for Developers


Step 10: Hot-Reloading for Faster Development

For many languages and frameworks, hot-reloading is essential for quick development feedback. In our example with Node.js, you can use nodemon to automatically reload the app when code changes. To use nodemon:

1. Install it in your Dockerfile:

Dockerfile
RUN npm install -g nodemon

2. Update your CMD to use nodemon:

Dockerfile
CMD ["nodemon", "index.js"]

Now your application will reload automatically, improving development speed.


Final Thoughts

confident cow with long hair letting it flow in the wind

Using Docker for local development environments is a game-changer, especially for complex applications with multiple dependencies. With Docker, you can eliminate issues related to inconsistent development setups, simplify your configuration management, and streamline your workflow. The commands and configuration files found here offer a foundational approach for using Docker in development. They allow you to take full advantage of Docker’s power and flexibility.

By mastering Docker for local development, you’re not only making your life easier but also preparing your application for a seamless transition to production environments. Happy coding!

Leave a Reply

I’m David

Welcome to my little corner of the internet that I dedicate to programming. I’m a principal software engineer at Fynix Consulting and strive to always be learning new things. I love to code and I love to write about coding!

Let’s connect

Discover more from David Boothe's Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading