Docker Swarm и Nginx, PHP. Вебсервер в кластере Docker Swarm. Часть 3. Traefik.

Опубликовано admin - чт, 10/03/2024 - 12:35
Docker Swarm Traefik

Продолжаем настройку кластера swarm.

В предыдущих статьях https://slyweb.ru/docker/docker-swarm-mysql и https://slyweb.ru/docker/swarm-and-web-server-clusters мы рассмотрели настройку docker swarm, php, mysql.

В этой статье мы попробуем добавить Traefik к уже существующему стэку Docker Swarm.
В предыдущей статье если Вы внимательно читали её, ip адрес отображается как ip адрес сети Docker, в реальных условиях это не совсем то, что надо.
В процессе выяснения вопроса как получить реальный ip, оказалось это не достаточно тривиальная задача.
В Docker Swarm можно использовать в секции port method: HOST, но тогда не будут работать реплики сервисов, которых больше чем одна.
Поэтому для решения этого вопроса, предлагаю использовать Traefik. Также у нас будет подключена стандартная dashboar от Traefik по https.

В прошлой статье мы закончили на файле index.php:

<?php
echo '<html><head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">

</head>
<body><div class="container">';
echo '<h2>Hello title</h2>';

echo '<p>Hello body <br/>';

echo '<p style="float:left;">
<img src="http://eapsite.ru/benjamin-voros-phIFdC6lA4E-unsplash.jpg" alt="Featued image for: Tutorial: Deploy a Full-Stack Application to a Docker Swarm" width="620" height="414"></p>
';


try {
    $dbh = new PDO('mysql:dbname=swtest_docker;host=0.0.0.0:4307', 'swtest', 'swtest');
} catch (PDOException $e) {
    die($e->getMessage());
}
$sth = $dbh->prepare("SELECT * FROM `Staff` WHERE `id` = ?");
$sth->execute(array('1'));
$array = $sth->fetch(PDO::FETCH_ASSOC);

function getUserIP()
{
    // Get real visitor IP behind CloudFlare network
    if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
              $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
              $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
    }
    $client  = @$_SERVER['HTTP_CLIENT_IP'];
    $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
    $remote  = $_SERVER['REMOTE_ADDR'];
    if(filter_var($client, FILTER_VALIDATE_IP))
    {
        $ip = $client;
    }
    elseif(filter_var($forward, FILTER_VALIDATE_IP))
    {
        $ip = $forward;
    }
    else
    {
        $ip = $remote;
    }
    return $ip;
}


$user_ip = getUserIP();
echo '<div style="clear:both;"><h2>Mysql</h2></div>';
echo '<br/>';

echo $user_ip; // Output IP address [Ex: 177.87.193.134]
//
echo '<br/>';
echo 'id ' . $array['id'] . '<br/>';
echo 'name ' .  $array['name'] . '<br/>';
echo 'birthday  ' . $array['birthday'] . '<br/>';

echo '<pre>';
print_r($_SERVER);
echo '</pre>';
echo '</div></body></html>';
?>

Как видно в нём есть функция getUserIP и вывод переменной $_SERVER, при отсутствии traefik, реальный ip адрес не удастся получить.

В docker-compose.yml необходим добавить новый сервис traefik:

traefik:
    image: "traefik:v3.1"
    container_name: "traefik"
    command:
      # Включите Docker Swarm в Traefik, чтобы он считывал метки из служб Docker
      - --providers.swarm.endpoint=unix:///var/run/docker.sock
      - --providers.swarm.network=backend
      # Добавьте ограничение на использование только сервисов с меткой "traefik.constraint-label=backend".
      - --providers.swarm.constraints=Label(`traefik.constraint-label`, `backend`)
      # Не предоставляйте доступ ко всем службам Docker, только к тем, которые явно доступны
      - --providers.swarm.exposedbydefault=false
      # Создайте точку входа "https", прослушивающую адрес 80
      - --entrypoints.http.address=:80
      # Создайте точку входа "https", прослушивающую адрес 443
      - --entrypoints.https.address=:443
      #- "--log.level=DEBUG"
      - --entryPoints.http.forwardedHeaders.trustedIPs=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7
      - --entrypoints.http.proxyProtocol.trustedIPs=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7
    ports:
        - "8080:8080"
        - target: 80
          published: 80
          protocol: tcp
          mode: host
        - "443:443"
      #- "80:80"
      #- "8080:8080"
    deploy:
       replicas: 1
       placement:
            constraints: [node.role == manager]
       labels:
        #Включите Traefik для этого сервиса, чтобы сделать его доступным в общедоступной сети
        - traefik.enable=true
        # Используйте общедоступную сеть backend(указанную ниже).
        - traefik.docker.network=backend
	# Используйте пользовательскую метку "traefik.constraint-label=backend" # Этот общедоступный      
	# Traefik будет использовать только службы с этой меткой 
	# Таким образом, при необходимости вы можете
	# добавить другие внутренние экземпляры Traefik в стек.
        - traefik.constraint-label=backend
	- traefik.http.routers.backend-http.rule=Host(`site.ru`)
        - traefik.http.routers.backend-http.entrypoints=web
        # Определите порт внутри используемой службы Docker
        - traefik.http.services.backend.loadbalancer.server.port=8080
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
     - backend

Давайте подробней разберем каждую опцию:

- traefik.enable=true
Взаимосвязана с опцией exposedByDefault, которая в свою очередь предоставляет доступ к контейнерам по умолчанию через Traefik. Если у exposedByDefault установлено значение false, контейнеры, у которых нет метки traefik.enable=true, игнорируются в результирующей конфигурации маршрутизации

- traefik.docker.network=backend
Определяет сеть docker по умолчанию, используемую для подключений ко всем контейнерам.

- traefik.constraint-label=backend
ограничивает применение определённых сервисов, в нашем случае в маршрутизации участвует контейнеры котрые помечены как backend

- traefik.http.routers.backend-http.rule=Host(`site.ru`)
Создаёт новый маршрут под названием “backend-http”, которому соответствует определенный хост

- traefik.http.routers.backend-http.entrypoints=web
Точки входа - это сетевые точки входа в Traefik. Они определяют порт, который будет принимать пакеты, и то, следует ли прослушивать TCP или UDP.
Точки входа у нас определены в разделе command “http” и “https”.
- --entrypoints.http.address=:80
- --entrypoints.https.address=:443
Подробная информация о точках входа указана по адресу: https://doc.traefik.io/traefik/routing/entrypoints/

- traefik.http.services.backend.loadbalancer.server.port=8080
По умолчанию Traefik использует первый открытый порт контейнера. Установка метки traefik.http.services.xxx.loadbalancer.server.port переопределяет это поведение.

Сейчас, как можно заметить, будет доступен реальный ip:

Docker Swarm Traefik

Итоговый файл docker-compose.yml

Взаимосвязанные материалы

# 1. Типичный пример Docker с Nginx и SSL (воскресенье, октября 6, 2024 - 15:33 ),
Типичный пример быстрой настройки Docker и Nginx c доступом по https. читать...
# 2. Docker Swarm и Nginx, PHP. Вебсервер в кластере Docker Swarm. Часть 4. Traefik и SSL Let's Encrypt: TLS (пятница, октября 4, 2024 - 23:31 ),

Небольшая статья - продолжение предыдущих трёх статей:

читать...
# 3. Docker Swarm и Nginx, PHP. Вебсервер в кластере Docker Swarm. Часть 3. Traefik. (четверг, октября 3, 2024 - 12:35 ),
Продолжаем настройку кластера Swarm. В этой статье мы попробуем добавить Traefik к уже существующему стэку Docker Swarm. читать...
# 4. Docker Swarm и Nginx, PHP. Вебсервер в кластере Docker Swarm. Часть 2. Mysql. (вторник, октября 1, 2024 - 11:53 ),
Docker Swarm и Nginx, PHP. Вебсервер в кластере Docker Swarm. Часть 2. Mysql. В этой статье мы попробуем добавить сервер mysql к уже существующему стэку Docker Swarm. читать...
# 5. Docker Swarm и Nginx, PHP. Вебсервер в кластере Docker Swarm. Часть 1. (понедельник, сентября 23, 2024 - 14:57 ),
С помощью Docker можно быстро развернуть рабочее web приложение с различными настройками и версиями. Docker Swarm выступает инструментом «оркестрации» контейнеров Docker, который позволяет управлять контейнерами как единое целое. читать...
На разработку сайта! Скидки до 20%!