Skip to content

Latest commit

 

History

History
592 lines (409 loc) · 22.1 KB

README.md

File metadata and controls

592 lines (409 loc) · 22.1 KB


WayOfDev Logo

Build Status Latest Stable Version Software License Commits since latest release Discord Link Follow on Twitter (X)

Docker Shared Services

This repository provides a Docker-powered local development environment for Dockerized projects, compatible with macOS and Linux.

It includes a set of docker-compose files and Træfik configuration with SSL support, backed by mkcert, to enable running a local network with custom DNS provided by dnsmasq. This setup facilitates developing microservices locally with access outside the Docker network.


🗂️ Table of Contents


🌟 Key Features

  • Automated Local DNS and SSL Setup: Eliminates manual edits to /etc/hosts and self-signed certificate warnings.
  • Consistent Development Environment: Uniform setup for all team members, reducing environment-related bugs.
  • Elimination of Port Conflicts: Traefik handles port management, allowing multiple dockerized projects to run concurrently.
  • User-Friendly Local URLs: Access projects via custom local domains like project.docker instead of localhost:8000.
  • Simplified CORS and Cookie Management: SSL support for local domains mirrors production settings.
  • Enhanced Testing Environment: Test OAuth, secure cookies, and HTTPS APIs locally.
  • Improved Service Discovery and Routing: Traefik automates service discovery and routing within your Docker network.
  • Ease of Integration with Existing Projects: Connect your existing Docker projects to this setup effortlessly.

🤔 Purpose

→ Simplifying Local Development

This project simplifies local development by addressing common issues such as:

  • Frequent updates to the /etc/hosts file.
  • Requirement of administrative access for changes.
  • Lack of SSL support for custom domains.
  • Port conflicts when forwarding Docker service ports to the host machine.
  • Use of cumbersome hostnames like localhost:8800 for local projects.
  • Complex CORS setup and Cookie configuration.

For Linux and macOS users, dnsmasq eliminates the need to edit the hosts file for each project, providing a streamlined solution when used with Traefik, mkcert, and Docker. This repository configures Traefik to work with dnsmasq, offering a system-wide DNS solution for microservices and enabling DNS and SSL features with local domains.


👏 Benefits for Team

→ Enhance Development Workflow

Integrating this Docker Shared Services project into your team's tech stack can significantly enhance your development workflow. This setup is compatible with a wide range of HTTP-based projects, including backend frameworks like Laravel, Symfony, or Spiral, frontend frameworks, and any other services that run in Docker and communicate over HTTP.

By standardizing the local network setup across different machines, your team can:

  • Maintain consistency.
  • Reduce configuration work.
  • Resolve port conflicts between multiple Docker services.
  • Provide SSL support for local domains.
  • Work with CORS and Cookies in a scenario close to production.
  • Set up OAuth providers to work with custom local domains.

This ensures smoother collaboration and boosts overall productivity.


If you like/use this project, please consider ⭐️ starring it. Thanks!


🚩 Requirements


💻 Quick Start Guide (macOS)

  1. Install Homebrew (if not installed):

    If Homebrew is not already installed, run the following command:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  2. Install Docker (if not installed):

    Set up Docker Desktop via Homebrew:

    brew install --cask docker
  3. Install mkcert and nss:

    mkcert is a tool that creates locally-trusted development certificates, and nss provides support for mkcert certificates in Firefox.

    brew install mkcert nss
  4. Create shared project directory:

    This repository should be run once per machine, so let's create a shared directory for this project:

    mkdir -p ~/projects/infra && cd ~/projects/infra
  5. Clone this repository:

    git clone \
      [email protected]:wayofdev/docker-shared-services.git \
      ~/projects/infra/docker-shared-services && \
    cd ~/projects/infra/docker-shared-services
  6. Create .env file:

    Generate a default .env file, which contains configuration settings for the project.

    make env

    Open this file and read the notes inside to make any necessary changes to fit your setup.

  7. Install root certificate and generate default project certs:

    This step installs the root certificate into your system's trust store and generates default SSL certificates for your local domains, which are listed in the .env file, under the variable TLS_DOMAINS.

    make cert-install

    [!WARNING]

    Currently, on macOS, you may need to enter your password several times to allow mkcert to install the root certificate. This is a one-time operation and details can be found in this upstream GitHub issue.

  8. Run this project:

    Start the Docker services defined in the repository.

    make up
  9. Check that all Docker services are running:

    Ensure Docker is running and services are up by using the make ps and make logs commands.

    make ps
    make logs
  10. Add custom DNS resolver to your system:

    This allows macOS to understand that *.docker domains should be resolved by a custom resolver via 127.0.0.1, where our DNSMasq, which runs inside Docker, will handle all DNS requests.

    sudo sh -c 'echo "nameserver 127.0.0.1" > /etc/resolver/docker'
    sudo dscacheutil -flushcache
    sudo killall -HUP mDNSResponder

    You can check that DNS was added by running:

    scutil --dns

    Example output:

    resolver #8
    domain   : docker
    nameserver[0] : 127.0.0.1
    flags    : Request A records, Request AAAA records
    reach    : 0x00030002 (Reachable,Local Address,Directly Reachable Address)

    [!NOTE]

    Instead of creating the /etc/resolver/docker file, you can add 127.0.0.1 to your macOS DNS Servers in your Ethernet or Wi-Fi settings.

    Go to System Preferences → Network → Wi-Fi → Details → DNS and add 127.0.0.1 as the first DNS server.

    This allows you to do it one time, and if you need to create a new local domain, for example *.mac, in the future, it will be automatically resolved without creating a separate /etc/resolver/mac file.

  11. Ping router.docker to check if DNS is working:

    Ensure that the DNS setup is functioning correctly.

    ping router.docker -c 3
    ping any-domain.docker -c 3
  12. Access Traefik dashboard:

    Open https://router.docker.

    You should see the Traefik Dashboard:

    Traefik dashboard

→ Outcome

At this point, you should have a working local development environment with DNS and SSL support ready to be used with your projects.

Services will be running under a shared Docker network called network.ss, and all projects or microservices that will share the same Docker network will be visible to Traefik. The local DNS, served by DNSMasq, will be available on *.docker domains.


🐧 Quick Start Guide (Linux)

In this section, we'll walk through setting up the docker-shared-services project on an Ubuntu distribution. While the steps are specific to Ubuntu, they should be adaptable to other Linux distributions with minor modifications.

  1. Install Docker: Easiest and quickest way to get started is to install Docker Desktop for Linux.

  2. Install certutil:

    sudo apt update
    sudo apt install libnss3-tools
  3. Install mkcert:

    curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"
    chmod +x mkcert-v*-linux-amd64
    sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert

    More detailed instructions can be found in the mkcert README.md.

  4. Create shared project directory:

    mkdir -p ~/projects/infra && cd ~/projects/infra
  5. Clone this repository:

    git clone \
      [email protected]:wayofdev/docker-shared-services.git \
      ~/projects/infra/docker-shared-services && \
    cd ~/projects/infra/docker-shared-services
  6. Create .env file:

    Generate a default .env file, which contains configuration settings for the project.

    make env

    Open this file and read the notes inside to make any necessary changes to fit your setup.

  7. Install root certificate and generate default project certs:

    make cert-install
  8. Disable stub DNS listener:

    To prevent conflicts with the DNSMasq service, disable the stub DNS listener in the systemd-resolved service.

    sudo sed -i 's/#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
    sudo systemctl restart systemd-resolved
  9. Edit /etc/resolv.conf:

    Update the /etc/resolv.conf file to use the local DNS server.

    echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf > /dev/null

    Editing /etc/resolv.conf directly is not recommended for persistent changes since it is often managed by other services (like Netplan or NetworkManager). However, for a temporary change, you can use:

  10. Run this project:

    Start the Docker services defined in the repository.

    make up
  11. Check that all Docker services are running:

    Ensure Docker is running and services are up by using the make ps and make logs commands.

    make ps
    make logs
  12. Ping router.docker to check if DNS is working:

    Ensure that the DNS setup is functioning correctly.

    ping router.docker -c 3
    ping any-domain.docker -c 3
  13. Access Traefik dashboard:

    Open https://router.docker.

    You should see the Traefik Dashboard:

    Traefik dashboard

→ Outcome

At this point, you should have a working local development environment with DNS and SSL support ready to be used with your projects.

Services will be running under a shared Docker network called network.ss, and all projects or microservices that will share the same Docker network will be visible to Traefik. The local DNS, served by DNSMasq, will be available on *.docker domains.


🔌 Connecting your Projects to Shared Services

To connect your projects to the shared services, configure your project's docker-compose.yaml file to connect to the shared network and Traefik.

This project comes with an example Portainer service, which also starts by default with the make up command. You can check the docker-compose.yaml to see how Traefik labels and the shared network are used to spin up Portainer on the https://ui.docker host, which supports SSL by default.

→ Sample Configuration

Your project should use the shared Docker network network.ss and Traefik labels to expose services to the outside world.

  1. Change your project's docker-compose.yaml file:

    ---
    
    services:
      web:
        image: wayofdev/nginx:k8s-alpine-latest
        restart: on-failure
    +   networks:
    +     - default
    +     - shared
        volumes:
          - ./app:/app:rw,cached
    +   labels:
    +     - traefik.enable=true
    +     - traefik.http.routers.api-my-project-secure.rule=Host(`api.my-project.docker`)
    +     - traefik.http.routers.api-my-project-secure.entrypoints=websecure
    +     - traefik.http.routers.api-my-project-secure.tls=true
    +     - traefik.http.services.api-my-project-secure.loadbalancer.server.port=8880
    +     - traefik.docker.network=network.ss
    
    networks:
    + shared:
    +   external: true
    +   name: network.ss
    + default:
    +   name: project.my-project

    In this configuration, we added the shared network and Traefik labels to the web service. These labels help Traefik route the traffic to the service based on the specified rules.

    Replace my-project with your preferred project name.

  2. Generate SSL certs for your project:

    Go to the docker-shared-services directory:

    cd ~/projects/infra/docker-shared-services

    Edit the .env file to add your custom domain:

    nano .env

    Add *.my-project.docker to end of TLS_DOMAINS variable:

    TLS_DOMAINS="ui.docker router.docker *.my-project.docker"

    Generate SSL certificates and reload docker-shared-services:

    make cert-install restart

🚀 Example: Spin-up Laravel Sail Project

Let's walk through an example of setting up a Laravel project using Sail and integrating it with the docker-shared-services.

  1. Create an example Laravel project based on Sail:

    curl -s "https://laravel.build/example-app" | bash
  2. Open the docker-compose.yaml file of the example-app project and make adjustments:

    services:
      laravel.test:
        build:
          context: ./vendor/laravel/sail/runtimes/8.3
          dockerfile: Dockerfile
          args:
            WWWGROUP: '${WWWGROUP}'
        image: sail-8.3/app
    -   extra_hosts:
    -     - 'host.docker.internal:host-gateway'
        ports:
    -     - '${APP_PORT:-80}:80'
    -     - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        networks:
          - sail
    +     - shared
        depends_on:
          - ...
    +   labels:
    +     - traefik.enable=true
    +     - traefik.http.routers.test-laravel-app-secure.rule=Host(`api.laravel-app.docker`)
    +     - traefik.http.routers.test-laravel-app-secure.entrypoints=websecure
    +     - traefik.http.routers.test-laravel-app-secure.tls=true
    +     - traefik.http.services.test-laravel-app-secure.loadbalancer.server.port=80
    +     - traefik.docker.network=network.ss
    
      mailpit:
        image: 'axllent/mailpit:latest'
        networks:
          - sail
    +     - shared
        ports:
    -     - '${FORWARD_MAILPIT_PORT:-1025}:1025'
    -     - '${FORWARD_MAILPIT_DASHBOARD_PORT:-8025}:8025'
    +   labels:
    +     - traefik.enable=true
    +     - traefik.http.routers.mail-laravel-app-secure.rule=Host(`mail.laravel-app.docker`)
    +     - traefik.http.routers.mail-laravel-app-secure.entrypoints=websecure
    +     - traefik.http.routers.mail-laravel-app-secure.tls=true
    +     - traefik.http.services.mail-laravel-app-secure.loadbalancer.server.port=8025
    +     - traefik.docker.network=network.ss
    
    networks:
      sail:
        driver: bridge
    + shared:
    +   external: true
    +   name: network.ss

    These changes connect the Laravel app and Mailpit docker services to the shared network and expose them via Traefik.

  3. Run the Laravel project:

    Navigate to the example-app directory and start the services using Sail.

    ./vendor/bin/sail up -d
  4. Check Traefik routers:

    Open https://router.docker/dashboard/#/http/routers and check that there are two routers:

    • Host(api.laravel-app.docker)test-laravel-app-secure@docker
    • Host(mail.laravel-app.docker)mail-laravel-app-secure@docker

    Traefik Routers

  5. Check the setup:

    Ensure that your Laravel application and Mailpit services are running correctly by accessing their respective domains:

At this point, your Laravel project is integrated with the wayofdev/docker-shared-services, utilizing DNS and SSL support for local development.


👀 Example: Want to See a Ready-Made Template?

If you come from the PHP or Laravel world, or if you want to see how a complete project can be integrated with docker-shared-services, check out wayofdev/laravel-starter-tpl.

This Dockerized Laravel starter template works seamlessly with wayofdev/docker-shared-services, providing a foundation with integrated DNS and SSL support, and can show you the way to implement patterns, stated in this article, in your projects.


🔒 Security Policy

This project has a security policy.


🙌 Want to Contribute?

Thank you for considering contributing to the wayofdev community! We are open to all kinds of contributions. If you want to:

You are more than welcome. Before contributing, kindly check our contribution guidelines.

Conventional Commits


🫡 Contributors

Contributors Badge

🌐 Social Links


📄 License

Licence