Dzisiaj na sysops'owo - przedstawię jak w prosty sposób stworzyć w swojej lokalnej sieci środowisko developerskie na kilka / kilkanaście projektów - w dodatku łatwe i elastyczne do rozbudowy.

 

Wykorzystamy do tego oczywiście tytułowego Docker'a oraz świetnie się nada ku temu także malinka (Raspberry Pi). Szybki koncepcyjny diagram:

 


 

Sama konfiguracja dockera nie będzie wielki problemem - jedynie główny server (service) Nginx'a należy odpowiednio podejść - wykorzystałem do tego reverse proxy oraz upstream.

 

Przykładowy docker-compose - wyposażony w Nginx'a (z certbotem do generowania certyfikatów SSL), baze danych (MariaDB), Redis'aa, Rabbit'a:

 

version: "3"

services:
  webserver:
    image: nginx:latest
    container_name: nginx
    hostname: nginx
    restart: unless-stopped
    volumes:
      - ./etc/nginx/conf:/etc/nginx/conf.d
      - ./etc/nginx/www/nginx-default:/var/www/nginx-default
      - ./etc/certbot/conf:/etc/letsencrypt
      - ./etc/certbot/www:/var/www/certbot
    ports:
      - "80:80"
      - "443:443"
    networks:
      - kosmcode

  certbot:
    image: certbot/certbot:latest
    container_name: certbot
    hostname: certbot
    volumes:
      - ./etc/certbot/conf/:/etc/letsencrypt
      - ./etc/certbot/www/:/var/www/certbot
    networks:
      - kosmcode

  mariadb:
    image: mariadb:latest
    container_name: mariadb
    hostname: mariadb
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD}"
    volumes:
      - mariadbData:/data/mysql/data
      - ./data/db_backup:/db_backup
      - ./etc/mariadb:/etc/mysql/conf.d
    ports:
      - "${MARIADB_PORT}:3306"
    networks:
      - kosmcode

  redis:
    image: redis:6.2-alpine
    restart: unless-stopped
    container_name: redis
    hostname: redis
    ports:
      - '${REDIS_PORT}:6379'
    volumes:
      - ./data/redis:/data
    networks:
      - kosmcode

  rabbitmq:
    image: rabbitmq:management
    container_name: rabbitmq
    restart: unless-stopped
    hostname: rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: "${RABBITMQ_USER}"
      RABBITMQ_DEFAULT_PASS: "${RABBITMQ_PASSWORD}"
    ports:
      - "${RABBITMQ_PORT}:5672"
      - "${RABBITMQ_ADMIN_PORT}:15672"
    networks:
      - kosmcode

networks:
  kosmcode:
    name: kosmcode-network

volumes:
  mariadbData:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: ./data/mariadb

 

Przykładowy .env

MARIADB_PORT=3306
MARIADB_ROOT_PASSWORD=""

REDIS_PASSWORD=""
REDIS_PORT=6379

RABBITMQ_PORT=5672
RABBITMQ_ADMIN_PORT=15672
RABBITMQ_USER="guest"
RABBITMQ_PASSWORD="guest"

 

Istotnym jest, aby wszystkie servicy były w jednym dockerowym networku - także osobnych aplikacji. Co do tego docker-compose nie ma wielkiej filozofii - w katalogu /etc przechowywane są różne dane serviców i tak:

  • /etc/certbot - wygenerowane klucze certyfikatów SSL
  • /etc/mariadb/my.cnf - plik konfiguracyjny dla bazy danych
  • /etc/nginx/conf/ - katalog przechowujący konfiguracje naszych stron (aplikacji)

 

Przykładowy plik konfiguracyjny dla nginx wygląda następująco:

upstream smartpassword {
    server {{ip_or_host_app_in_network}}:{{app_port}};
}

server {
    listen 80;
    listen [::]:80;

    server_name {{site_domain}};
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://smart-password.net$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name {{site_domain}};

    ssl_certificate /etc/letsencrypt/live/{{site_domain}}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/{{site_domain}}/privkey.pem;

    location / {
        proxy_pass         http://smartpassword;
        proxy_redirect     off;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }
}

 

Oczywiście to najprostsza konfiguracja - wedle potrzeb można (a nawet trzeba) modyfikować - cache, kompresje, dodatkowe header'y które mają być przekazywane itd. Natomiast co do:

  • {{ip_or_host_app_in_network}} - w upstream należy podać ip lub host naszej aplikacji, do której proxy ma być czynione. Może to być aplikacja oparta na osobnym service nginx, self-hostowana, sail dockera, octane, caddy czy django / flask python'owski np. ;) Czego akurat potrzebujemy, co obsługuje protokół HTTP/S tak naprawdę.
  • {{app_port}} - port naszej aplikacji, który jest wystawiony na zewnątrz.
  • {{site_domain}} - nazwę naszego service'u / domenę. Może to być lokalny adres servera w sieci lub jego subdomena, a także zwykła domena (jeżeli zdecydujemy się udostępniać / hostować zasoby poza naszą sieć lokalną).

 

Przyznam się, że sam hostuje kilka swoich mniejszych projektów na zewnątrz z sieci lokalnej - za server'ek służy mi właśnie Raspberry Pi 4B i byłem bardzo miło zaskoczony, jak dobrze znosi trudy dokeryzacji różnych usług / service'ów. Baa pozostawiając nawet jeszcze duże zasoby do działania - oczywiście nie są to sklepy produkcyjne, portale w dużym ruchem itp. aplikacje (to raczej by było szaleństwo). Ale mniejsze stronki dają jak najbardziej radę ;).

 

No to jak już mamy wszystko przygotowane - to wystarczy jedynie zbudować obraz, zrobić up -d - wygenerować certyfikaty jeżeli potrzebujemy, zrestartować i powinno działać.

 

U mnie działa - jak to się nawykło mawiać a naszej branży ;)