Swiftorial Logo
Home
Swift Lessons
Tutorials
Learn More
Career
Resources

Docker Compose

Docker Compose is a tool for defining and running multi-container Docker applications. It uses a YAML file to configure the application's services. This guide covers key concepts, steps to create and manage Docker Compose files, examples, and best practices for using Docker Compose with Express.js applications.

Key Concepts of Docker Compose

  • Services: A service is a definition of a container. It specifies which image to use and other details like ports and volumes.
  • Networks: Networks allow services to communicate with each other.
  • Volumes: Volumes provide persistent storage for Docker containers.
  • docker-compose.yml: The YAML file that defines the services, networks, and volumes for a Docker application.

Setting Up the Project

Initialize a new Express.js project and create a Dockerfile:

// Initialize a new project
// npm init -y

// Install Express
// npm install express

// Create the project structure
// mkdir src
// touch src/index.js Dockerfile .dockerignore .gitignore docker-compose.yml

// .gitignore
node_modules
.env

// .dockerignore
node_modules
npm-debug.log

Creating an Express Application

Create a simple Express application:

Example: index.js

// src/index.js
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
    res.send('Hello, Docker Compose!');
});

app.listen(port, () => {
    console.log(`Server running at http://localhost:${port}/`);
});

Creating a Dockerfile

Create a Dockerfile to containerize your Express application:

Example: Dockerfile

// Dockerfile
FROM node:14

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./
RUN npm install

# Bundle app source
COPY . .

# Make port 3000 available to the world outside this container
EXPOSE 3000

# Run app when the container launches
CMD ["node", "src/index.js"]

Creating a Docker Compose File

Create a docker-compose.yml file to define the services, networks, and volumes for your Docker application:

Example: docker-compose.yml

// docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/usr/src/app
    environment:
      - NODE_ENV=development

Using Docker Compose Commands

Use Docker Compose commands to manage the Docker containers defined in the docker-compose.yml file:

Build and Start the Containers

// Build and start the containers
docker-compose up --build

// Open http://localhost:3000 in your browser to see the application running

Stop the Containers

// Stop the containers
docker-compose down

View the Logs

// View the logs of the containers
docker-compose logs

Run a Command in a Service

// Run a command in a service
docker-compose exec web /bin/bash

Scale Services

// Scale services to run multiple instances
docker-compose up --scale web=3

Best Practices for Using Docker Compose

  • Keep Compose Files Simple: Write clear and concise docker-compose.yml files to make them easy to understand and maintain.
  • Use Environment Variables: Store configuration settings in environment variables to keep your services environment-agnostic.
  • Use Volumes for Development: Mount the code directory as a volume in the container for easier development.
  • Leverage Caching: Place instructions that are less likely to change at the top of the Dockerfile to leverage Docker's caching mechanism.
  • Isolate Services: Define networks and volumes to isolate services and manage dependencies effectively.
  • Automate Builds: Use CI/CD pipelines to automate the building, testing, and deployment of your Docker images.

Testing Docker Compose Integration

Test your Docker Compose setup to ensure it works correctly:

Example: Testing with Mocha and Chai

// Install Mocha and Chai
// npm install --save-dev mocha chai

// test/app.test.js
const chai = require('chai');
const expect = chai.expect;
const axios = require('axios');

describe('Express App', () => {
    it('should return Hello, Docker Compose!', async () => {
        const response = await axios.get('http://localhost:3000');
        expect(response.data).to.equal('Hello, Docker Compose!');
    });
});

// Add test script to package.json
// "scripts": {
//   "test": "mocha"
// }

// Run tests
// docker-compose up --build
// npm test

Key Points

  • Services: A service is a definition of a container. It specifies which image to use and other details like ports and volumes.
  • Networks: Networks allow services to communicate with each other.
  • Volumes: Volumes provide persistent storage for Docker containers.
  • docker-compose.yml: The YAML file that defines the services, networks, and volumes for a Docker application.
  • Follow best practices for using Docker Compose, such as keeping Compose files simple, using environment variables, using volumes for development, leveraging caching, isolating services, and automating builds.

Conclusion

Docker Compose is a powerful tool for defining and running multi-container Docker applications. By understanding and implementing the key concepts, steps, examples, and best practices covered in this guide, you can effectively use Docker Compose to manage your Express.js applications. Happy coding!