One place for hosting & domains

      Docker

      Установка WordPress с помощью Docker Compose


      Введение

      WordPress — бесплатная система управления контентом (CMS) с открытым исходным кодом, которая опирается на базу данных MySQL и обрабатывает запросы с помощью PHP. Благодаря огромному количеству плагинов и системе шаблонов, а также тому факту, что большая часть административных функций может производиться через веб-интерфейс, WordPress завоевала популярность среди создателей самых разных сайтов, от блогов и страниц с описанием продукта и до сайтов электронной торговли.

      Для запуска WordPress, как правило, требуется установка стека LAMP (Linux, Apache, MySQL и PHP) или LEMP (Linux, Nginx, MySQL и PHP), что может занять много времени. С помощью таких инструментов, как Docker и Docker Compose, вы можете упростить процесс настройки предпочитаемого стека и установки WordPress. Вместо установки отдельных компонентов вручную, вы можете использовать образы, которые обладают такими стандартными элементами как библиотеки, файлы конфигурации и переменные среды, и запускать эти образы в контейнерах, т.е. изолированных процессов, запущенных в общей операционной системе. Кроме того, используя Compose, вы можете координировать действия нескольких контейнеров, например, приложения и базы данных, которые будут коммуницировать друг с другом.

      В этом обучающем руководстве вы будете выполнять установку WordPress с несколькими контейнерами. Ваши контейнеры будут включать базу данных MySQL, веб-сервер Nginx и непосредственно WordPress. Также вы должны будете обеспечить защиту установки, получая с помощью Let’s Encrypt​​​​​​ сертификаты TLS/SSL для доменов, которые вы хотите привязать к вашему сайту. Наконец, вы настроите задание cron для обновления ваших сертификатов, чтобы ваш домен оставался защищенным.

      Предварительные требования

      Для данного обучающего модуля вам потребуется следующее:

      • Сервер на базе Ubuntu 18.04, а также пользователь без прав root с привилегиями sudo и активный брандмауэр. Дополнительную информацию о настройке этих параметров см. в руководстве по первоначальной настройке сервера.
      • Система Docker, установленная на сервере в соответствии с шагами 1 и 2 руководства «Установка и использование Docker в Ubuntu 18.04».
      • Docker Compose, установленный на сервере, в соответствии с шагом 1 руководства Установка Docker Compose в Ubuntu 18.04.
      • Зарегистрированное доменное имя. В этом обучающем руководстве мы будем использовать example.com. Вы можете получить бесплатный домен на Freenom или зарегистрировать доменное имя по вашему выбору.
      • На вашем сервере должны быть настроены обе нижеследующие записи DNS. Вы можете воспользоваться введением в работу с DigitalOcean DNS, чтобы получить подробную информацию о добавлении доменов в учетную запись DigitalOcean, если вы используете этот способ:

        • Запись A, где example.com указывает на публичный IP-адрес вашего сервера.
        • Запись A, где www.example.com указывает на публичный IP-адрес вашего сервера.

      Шаг 1 — Настройка конфигурации веб-сервера

      Перед запуском контейнеров прежде всего необходимо настроить конфигурацию нашего веб-сервера Nginx. Наш файл конфигурации будет включать несколько специфических для WordPress блоков расположения наряду с блоками расположения, которые будут направлять передаваемые Let’s Encrypt запросы верификации клиенту Certbot для автоматизированного обновления сертификатов.

      Во-первых, создайте директорию проекта для настройки WordPress с именем < wordpress и перейдите в эту директорию:

      • mkdir wordpress && cd wordpress

      Затем создайте директорию для файла конфигурации:

      Откройте файл с помощью nano или своего любимого редактора:

      • nano nginx-conf/nginx.conf

      В этом файле мы добавим серверный блок с директивами для имени нашего сервера и корневого каталога документов, а также блок расположения для направления запросов сертификатов от клиента Certbot, обработки PHP и запросов статичных активов.

      Добавьте в файл следующий код. Обязательно замените example.com на ваше доменное имя.

      ~/wordpress/nginx-conf/nginx.conf

      server {
              listen 80;
              listen [::]:80;
      
              server_name example.com www.example.com;
      
              index index.php index.html index.htm;
      
              root /var/www/html;
      
              location ~ /.well-known/acme-challenge {
                      allow all;
                      root /var/www/html;
              }
      
              location / {
                      try_files $uri $uri/ /index.php$is_args$args;
              }
      
              location ~ .php$ {
                      try_files $uri =404;
                      fastcgi_split_path_info ^(.+.php)(/.+)$;
                      fastcgi_pass wordpress:9000;
                      fastcgi_index index.php;
                      include fastcgi_params;
                      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                      fastcgi_param PATH_INFO $fastcgi_path_info;
              }
      
              location ~ /.ht {
                      deny all;
              }
      
              location = /favicon.ico {
                      log_not_found off; access_log off;
              }
              location = /robots.txt {
                      log_not_found off; access_log off; allow all;
              }
              location ~* .(css|gif|ico|jpeg|jpg|js|png)$ {
                      expires max;
                      log_not_found off;
              }
      }
      

      Наш серверный блок содержит следующую информацию:

      Директивы:

      • listen: данный элемент просит Nginx прослушивать порт 80, что позволит нам использовать плагин webroot Certbot для наших запросов сертификатов. Обратите внимание, что мы пока не будем включать порт 443, мы обновим нашу конфигурацию и добавим SSL после успешного получения наших сертификатов.
      • server_name: этот элемент определяет имя вашего сервера и серверный блок, который должны использоваться для запросов к вашему серверу. Обязательно замените example.com в этой строке на ваше собственное доменное имя.
      • index: директива index определяет файлы, которые будут использоваться в качестве индексов при обработке запросов к вашему серверу. Здесь мы изменили порядок приоритета по умолчанию, поставив index.html перед index.html, в результате чего Nginx будет давать приоритет файлам с именем index.php при наличии возможности.
      • root: наша директива root назначает имя корневой директории для запросов к нашему серверу. Эта директория, /var/www/html, создается в качестве точки монтирования в момент сборки с помощью инструкций в Dockerfile WordPress. Эти инструкции Dockerfile также гарантируют, что файлы релиза WordPress монтируются в этот том.

      Блоки расположения:

      • location ~ /.well-known/acme-challenge: этот блок расположения будет обрабатывать запросы в директории .well-known, где Certbot будет размещать временный файл для подтверждения того, что DNS для нашего домена будет работать с нашим сервером. Настроив данную конфигурацию, мы сможем использовать плагин webroot Certbot для получения сертификатов для нашего домена.
      • location /: в этом блоке расположения мы будем использовать директиву try_files для проверки файлов, соответствующих отдельным запросам URI. Вместо того, чтобы возвращать по умолчанию статус 404 не найдено, мы будем передавать контроль файлу index.php WordPress с аргументами запроса.
      • location ~.php$: этот блок расположения будет обрабатывать PHP запросы и проксировать эти запросы в наш контейнер wordpress. Поскольку наш образ WordPress Docker будет опираться на образ php:fpm, мы также добавим параметры конфигурации, принадлежащие протоколу FastCGI, в этом блоке. Nginx требует наличия независимого процессора PHP для запросов PHP: в нашем случае эти запросы будут обрабатываться процессором php-fpm, который будет включать образ php:fpm. Кроме того, этот блок расположения содержит директивы FastCGI, переменные и опции, которые будут проксировать запросы для приложения WordPress, запущенного в нашем контейнере wordpress, задавать предпочитаемый индекс захваченного URI запроса, а также выполнять парсинг URI запросов.
      • location ~ /.ht: этот блок будет обрабатывать файлы .htaccess, поскольку Nginx не будет обслуживать их. Директива deny_all гарантирует, что файлы .htaccess никогда не будут отображаться для пользователей.
      • location = /favicon.ico, location = /robots.txt: эти блоки гарантируют, что запросы для /favicon.ico и /robots.txt не будут регистрироваться.
      • location ~* (css|gif|ico|jpeg|jpg|js|png)$: этот блок отключает запись в журнал для запросов статичных активов и гарантирует, что эти активы будут иметь высокую кэшируемость, поскольку обычно их трудно обслуживать.

      Дополнительную информацию о проксировании FastCGI см. в статье Понимание и реализация проксирования FastCGI в Nginx. Информацию о серверных блоках и блоках расположения см. в статье Знакомство с сервером Nginx и алгоритмы выбора блоков расположения.

      Сохраните и закройте файл после завершения редактирования. Если вы используете nano, нажмите CTRL+X, Y, затем ENTER.

      После настройки конфигурации Nginx вы можете перейти к созданию переменных среды для передачи в контейнеры приложения и базы данных во время исполнения.

      Шаг 2 — Настройка переменных среды

      Контейнеры базы данных и приложения WordPress должны получить доступ к определенным переменным среды в момент выполнения для сохранения данных приложения и предоставления доступа к этим данным для вашего приложения. Эти переменные включают чувствительные и нечувствительные данные: к чувствительным данным относятся root пароль MySQL и пароль и пользователь базы данных приложения, а к нечувствительным данным относится информация о имени и хосте базы данных приложения.

      Вместо того, чтобы задавать эти значения в нашем файле Docker Compose, основном файле, который содержит информацию о том, как наши контейнеры будут работать, мы можем задать чувствительные значения в файле .env и ограничить его распространение. Это не позволит скопировать эти значения в репозиторий нашего проекта и открыть их для общего доступа.

      В главной директории проекта ~/wordpress, откройте файл с именем .env:

      Конфиденциальные значения, которые мы зададим в этом файле, включают пароль для нашего root пользователя MySQL, имя пользователя и пароль, которые WordPress будет использовать для доступа к базе данных.

      Добавьте в файл следующие имя и значения переменных: Обязательно предоставьте здесь ваши собственные значения для каждой переменной:

      ~/wordpress/.env

      MYSQL_ROOT_PASSWORD=your_root_password
      MYSQL_USER=your_wordpress_database_user
      MYSQL_PASSWORD=your_wordpress_database_password
      

      Мы включили пароль для административной учетной записи root, а также предпочитаемые имя пользователя и пароль для нашей базы данных приложения.

      Сохраните и закройте файл после завершения редактирования.

      Поскольку ваш файл .env содержит чувствительную информацию, вы можете убедиться, что в файлы .gitignore и .dockerignore вашего проекта включены инструкции, указывающие Git и Docker, какие файлы не копировать в ваши репозитории Git и образы Docker.

      Если вы планируете использовать Git для контроля версий, инициализируйте текущую рабочую директорию в качестве репозитория с помощью git init:

      Затем откройте файл .gitignore:

      Добавьте .env в файл:

      ~/wordpress/.gitignore

      .env
      

      Сохраните и закройте файл после завершения редактирования.

      Также в качестве дополнительной меры предосторожности рекомендуется добавить .env в файл .dockerignore, чтобы он не потерялся в ваших контейнерах, когда вы используете эту директорию в качестве контекста для сборки.

      Откройте файл:

      Добавьте .env в файл:

      ~/wordpress/.dockerignore

      .env
      

      Ниже вы можете дополнительно добавить файлы и директории, связанные с разработкой вашего приложения:

      ~/wordpress/.dockerignore

      .env
      .git
      docker-compose.yml
      .dockerignore
      

      Сохраните файл и закройте его после завершения.

      Теперь, когда все чувствительные данные на месте, вы можете перейти к определению ваших служб в файле docker-compose.yml.

      Шаг 3 — Определение служб с помощью Docker Compose

      Ваш файл docker-compose.yml будет содержать определения службы для вашей настройки. Служба в Compose — это запущенный контейнер, а определения службы содержат информацию о том, как каждый контейнер будет работать.

      Используя Compose, вы можете определить различные службы для запуска приложений с несколькими контейнерами, поскольку Compose позволяет привязать эти службы к общим сетям и томам. Это будет полезно для нашей текущей настройки, поскольку мы создадим различные контейнеры для нашей базы данных, приложения WordPress и веб-сервера. Также мы создадим контейнер для запуска клиента Certbot, чтобы получить сертификаты для нашего веб-сервера.

      Откройте файл docker-compose.yml:

      Добавьте следующий код для определения версии файла Compose и базы данных db:

      ~/wordpress/docker-compose.yml

      version: '3'
      
      services:
        db:
          image: mysql:8.0
          container_name: db
          restart: unless-stopped
          env_file: .env
          environment:
            - MYSQL_DATABASE=wordpress
          volumes:
            - dbdata:/var/lib/mysql
          command: '--default-authentication-plugin=mysql_native_password'
          networks:
            - app-network
      

      Определение службы db включает следующие параметры:

      • image: данный элемент указывает Compose, какой образ будет загружаться для создания контейнера. Мы закрепим здесь образ mysql:8.0, чтобы избежать будущих конфликтов, так как образ mysql:latest продолжит обновляться. Дополнительную информацию о закреплении версии и предотвращении конфликтов зависимостей см. документацию Docker и раздел Рекомендации по работе с Dockerfile.
      • container_name: данный элемент указывает имя контейнера.
      • restart: данный параметр определяет политику перезапуска контейнера. По умолчанию установлено значение no, но мы задали значение, согласно которому контейнер будет перезапускаться, пока не будет остановлен вручную.
      • env_file: этот параметр указывает Compose, что мы хотим добавить переменные среды из файла с именем .env, расположенного в контексте сборки. В этом случае в качестве контекста сборки используется наша текущая директория.
      • environment: этот параметр позволяет добавить дополнительные переменные среды, не определенные в файле .env. Мы настроим переменную MYSQL_DATABASE со значением wordpress, которая будет предоставлять имя нашей базы данных приложения. Поскольку эта информация не является чувствительной, мы можем включить ее напрямую в файл docker-compose.yml.
      • volumes: здесь мы монтируем именованный том с названием dbdata в директорию /var/lib/mysql в контейнере. Это стандартная директория данных для в большинстве дистрибутивов.
      • command: данный параметр указывает команду, которая будет переопределять используемое по умолчанию значение инструкции CMD для образа. В нашем случае мы добавим параметр для стандартной команды mysqld образа Docker, которая запускает сервер MySQL в контейнере. Эта опция --default-authentication-plugin=mysql_native_password устанавливает для системной переменной --default-authentication-plugin значение mysql_native_password, которое указывает, какой механизм аутентификации должен управлять новыми запросами аутентификации для сервера. Поскольку PHP и наш образ WordPress не будут поддерживать новое значение аутентификации MySQL по умолчанию, мы должны внести изменения, чтобы выполнить аутентификацию пользователя базы данных приложения.
      • networks: данный параметр указывает, что служба приложения будет подключаться к сети app-network, которую мы определим внизу файла.

      Затем под определением службы db добавьте определение для вашей службы приложения wordpress:

      ~/wordpress/docker-compose.yml

      ...
        wordpress:
          depends_on:
            - db
          image: wordpress:5.1.1-fpm-alpine
          container_name: wordpress
          restart: unless-stopped
          env_file: .env
          environment:
            - WORDPRESS_DB_HOST=db:3306
            - WORDPRESS_DB_USER=$MYSQL_USER
            - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
            - WORDPRESS_DB_NAME=wordpress
          volumes:
            - wordpress:/var/www/html
          networks:
            - app-network
      

      В этом определении службы мы называем наш контейнер и определяем политику перезапуска, как уже делали это для службы db. Также мы добавляем в этот контейнер ряд параметров:

      • depends_on: этот параметр гарантирует, что наши контейнеры будут запускаться в порядке зависимости, и контейнер wordpress запускается после контейнера db. Наше приложение WordPress зависит от наличия базы данных приложения и пользователя, поэтому установка такого порядка зависимостей позволит выполнять запуск приложения корректно.
      • image: для этой настройки мы будем использовать образ WordPress 5.11-fpm-alpine. Как было показано в шаге 1, использование этого образа гарантирует, что наше приложение будет иметь процессор php-fpm, который требуется Nginx для обработки PHP. Это еще и образ alpine, полученный из проекта Alpine Linux, который поможет снизить общий размер образа. Дополнительную информацию о преимуществах и недостатках использования образов alpine, а также о том, имеет ли это смысл в случае вашего приложения, см. полное описание в разделе Варианты образа на странице образа WordPress на Docker Hub.
      • env_file: и снова мы укажем, что хотим загрузить значения из файла .env, поскольку там мы определили пользователя базы данных приложения и пароль.
      • environment: здесь мы будем использовать значения, определенные в файле .env, но мы привяжем их к именам переменных, которые требуются для образа WordPress: WORDPRESS_DB_USER и WORDPRESS_DB_PASSWORD. Также мы определяем значение WORDPRESS_DB_HOST, которое будет указывать сервер MySQL, который будет работать в контейнере db, доступный на используемом по умолчанию порту MySQL 3306. Наше значение WORDPRESS_DB_NAME будет тем же, которое мы указали при определении службы MySQL для MYSQL_DATABASE: wordpress.
      • volumes: мы монтируем том с именем wordpress на точку монтирования /var/www/html, созданную образом WordPress. Использование тома с именем таким образом позволит разделить наш код приложения с другими контейнерами.
      • networks: мы добавляем контейнер wordpress в сеть app-network.

      Далее под определением службы приложения wordpress добавьте следующее определение для службы Nginx webserver:

      ~/wordpress/docker-compose.yml

      ...
        webserver:
          depends_on:
            - wordpress
          image: nginx:1.15.12-alpine
          container_name: webserver
          restart: unless-stopped
          ports:
            - "80:80"
          volumes:
            - wordpress:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - app-network
      

      Мы снова присвоим имя нашему контейнеру и сделаем его зависимым от контейнера wordpress в отношении порядка запуска. Также мы используем образ alpine — образ Nginx 1.15.12-alpine.

      Это определение службы также включает следующие параметры:

      • ports: этот параметр открывает порт 80, чтобы активировать параметры конфигурации, определенные нами в файле nginx.conf в шаге 1.
      • volumes: здесь мы определяем комбинацию названных томов и связанных монтируемых образов:
        • wordpress:/var/www/html: этот параметр будет монтировать код нашего приложения WordPress в директорию /var/www/html, директорию, которую мы задали в качестве root директории в нашем серверном блоке Nginx.
        • ./nginx-conf:/etc/nginx/conf.d: этот элемент будет монтировать директорию конфигурации Nginx на хост в соответствующую директорию в контейнере, гарантируя, что любые изменения, которые мы вносим в файлы на хосте, будут отражены в контейнере.
        • certbot-etc:/etc/letsencrypt: этот элемент будет монтировать соответствующие сертификаты и ключи Let’s Encrypt для нашего домена в соответствующую директорию контейнера.

      Здесь мы снова добавили этот контейнер в сеть app-network.

      Наконец, под определением webserver добавьте последнее определение для службы certbot. Обязательно замените адрес электронной почты и доменные имена, перечисленные здесь, на ваши собственные:

      ~/wordpress/docker-compose.yml

        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - wordpress:/var/www/html
          command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com
      

      Это определение попросит Compose извлекать образ certbot/certbot из Docker Hub. Также оно использует имена томов для обмена ресурсами с контейнером Nginx, включая доменные сертификаты и ключ в certbot-etc и код приложения в wordpress.

      Мы использовали depends_on, чтобы указать, что контейнер certbot следует запускать только после запуска службы webserver.

      Также мы включили параметр command, указывающий субкоманду для запуска с используемой контейнером по умолчанию командой certbot. Субкоманда certonly будет получать сертификат со следующими параметрами:

      • --webroot: данный элемент говорит Certbot о необходимости использования плагина webroot для размещения файлов в папке webroot для аутентификации. Работа плагина основана на методе валидации HTTP-01, который использует запрос HTTP, чтобы доказать, что Certbot может получить доступ к ресурсам с сервера, который отвечает на заданное доменное имя.
      • --webroot-path: данный элемент указывает путь директории webroot.
      • --email: предпочитаемый адрес электронной почты для регистрации и восстановления.
      • --agree-tos: данный элемент указывает, что вы принимаете Соглашение о подписке ACME.
      • --no-eff-email: данный элемент указывает Certbot, что вы не хотите делиться адресом электронной почты с Electronic Frontier Foundation​​​ (EFF). Вы можете пропустить этот элемент.
      • --staging: данный элемент говорит Certbot, что вы хотите использовать промежуточную среду Let’s Encrypt для получения тестовых сертификатов. При использовании этого параметра вы можете протестировать параметры конфигурации и избежать возможных пределов для запросов домена. Дополнительную информацию об этих предельных значениях см. в документации по ограничениям скорости Let’s Encrypt.
      • -d: данный элемент позволяет указать доменные имена, которые вы хотите использовать для вашего запроса. В нашем случае мы включили example.com и www.example.com. Обязательно замените эти данные на имя вашего домена.

      Под определением службы certbot добавьте определения сети и тома:

      ~/wordpress/docker-compose.yml

      ...
      volumes:
        certbot-etc:
        wordpress:
        dbdata:
      
      networks:
        app-network:
          driver: bridge  
      

      Наш ключ верхнего уровня volumes определяет тома certbot-etc, wordpress и dbdata. Когда Docker создает тома, содержимое тома сохраняется в директории файловой системы хоста, /var/lib/docker/volumes/, а данным процессом управляет Docker. После этого содержимое каждого тома монтируется из этой директории в любой контейнер, использующий том. Таким образом мы можем делиться кодом и данными между контейнерами.

      Создаваемая пользователем мостовая система app-network позволяет организовать коммуникацию между нашими контейнерами, поскольку они находятся на одном хосте демона Docker. Это позволяет организовать трафик и коммуникации внутри приложения, поскольку она открывает все порты между контейнерами в одной мостовой сети, скрывая все порты от внешнего мира. Таким образом, наши контейнеры db, wordpress и webserver могут взаимодействовать друг с другом, и нам нужно будет только открыть порт 80 для внешнего доступа к приложению.

      Итоговый файл docker-compose.yml будет выглядеть примерно так:

      ~/wordpress/docker-compose.yml

      version: '3'
      
      services:
        db:
          image: mysql:8.0
          container_name: db
          restart: unless-stopped
          env_file: .env
          environment:
            - MYSQL_DATABASE=wordpress
          volumes:
            - dbdata:/var/lib/mysql
          command: '--default-authentication-plugin=mysql_native_password'
          networks:
            - app-network
      
        wordpress:
          depends_on:
            - db
          image: wordpress:5.1.1-fpm-alpine
          container_name: wordpress
          restart: unless-stopped
          env_file: .env
          environment:
            - WORDPRESS_DB_HOST=db:3306
            - WORDPRESS_DB_USER=$MYSQL_USER
            - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
            - WORDPRESS_DB_NAME=wordpress
          volumes:
            - wordpress:/var/www/html
          networks:
            - app-network
      
        webserver:
          depends_on:
            - wordpress
          image: nginx:1.15.12-alpine
          container_name: webserver
          restart: unless-stopped
          ports:
            - "80:80"
          volumes:
            - wordpress:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - app-network
      
        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - wordpress:/var/www/html
          command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com -d www.example.com
      
      volumes:
        certbot-etc:
        wordpress:
        dbdata:
      
      networks:
        app-network:
          driver: bridge  
      

      Сохраните и закройте файл после завершения редактирования.

      После добавления определений службы вы можете запустить контейнеры и протестировать запросы сертификата.

      Шаг 4 — Получение сертификатов SSL и учетных данных

      Мы можем запустить наши контейнеры с помощью команды docker-compose up, которая будет создавать и запускать наши контейнеры и службы в указанном нами порядке. Если наши запросы доменов будут выполнены успешно, мы увидим корректный статус выхода в нашем выводе и нужные сертификаты, установленные в папке /etc/letsencrypt/live на контейнере webserver.

      Создайте контейнеры с помощью команды docker-compose up и флага -d, которые будут запускать контейнеры db​​​, wordpress и webserver в фоновом режиме:

      Вы увидите вывод, подтверждающий, что ваши службы были успешно созданы:

      Output

      Creating db ... done Creating wordpress ... done Creating webserver ... done Creating certbot ... done

      С помощью docker-compose ps проверьте статус ваших служб:

      Если все будет выполнено успешно, ваши службы db, wordpress и webserver должны иметь статус Up, а работа контейнера certbot будет завершена с сообщением о статусе 0:

      Output

      Name Command State Ports ------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp wordpress docker-entrypoint.sh php-fpm Up 9000/tcp

      Если вы увидите любое значение, кроме Up в столбце State для служб db, wordpress и webserver, или любое сообщение о статусе выхода, отличающееся от 0, для контейнера certbot, проверьте журналы службы с помощью команды docker-compose logs:

      • docker-compose logs service_name

      Теперь вы можете убедиться, что ваши сертификаты были смонтированы в контейнер webserver с помощью команды docker-compose exec:

      • docker-compose exec webserver ls -la /etc/letsencrypt/live

      Если запросы сертификата были выполнены успешно, вы увидите следующий результат:

      Output

      total 16 drwx------ 3 root root 4096 May 10 15:45 . drwxr-xr-x 9 root root 4096 May 10 15:45 .. -rw-r--r-- 1 root root 740 May 10 15:45 README drwxr-xr-x 2 root root 4096 May 10 15:45 example.com

      Теперь, когда вы убедились, что ваш запрос будет выполнен успешно, вы можете изменить определение службы certbot для удаления флага --staging.

      Откройте docker-compose.yml:

      Найдите раздел файла с определением службы certbot и замените флаг --staging в параметрах command на флаг --force-renewal, который будет указывать Certbot, что вы хотите запросить новый сертификат с теми же доменами, что и в уже существующем сертификате. Определение службы certbot должно будет выглядеть следующим образом:

      ~/wordpress/docker-compose.yml

      ...
        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - certbot-var:/var/lib/letsencrypt
            - wordpress:/var/www/html
          command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
      ...
      

      Теперь вы можете запустить команду docker-compose up для воссоздания контейнера certbot. Также мы будем использовать параметр --no-deps, чтобы сообщить Compose о том, что можно пропустить запуск службы webserver, поскольку она уже запущена:

      • docker-compose up --force-recreate --no-deps certbot

      Вы увидите вывод, указывающий, что запрос сертификата выполнен успешно:

      Output

      Recreating certbot ... done Attaching to certbot certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | Plugins selected: Authenticator webroot, Installer None certbot | Renewing an existing certificate certbot | Performing the following challenges: certbot | http-01 challenge for example.com certbot | http-01 challenge for www.example.com certbot | Using the webroot path /var/www/html for all unmatched domains. certbot | Waiting for verification... certbot | Cleaning up challenges certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/example.com/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/example.com/privkey.pem certbot | Your cert will expire on 2019-08-08. To obtain a new or tweaked certbot | version of this certificate in the future, simply run certbot certbot | again. To non-interactively renew *all* of your certificates, run certbot | "certbot renew" certbot | - Your account credentials have been saved in your Certbot certbot | configuration directory at /etc/letsencrypt. You should make a certbot | secure backup of this folder now. This configuration directory will certbot | also contain certificates and private keys obtained by Certbot so certbot | making regular backups of this folder is ideal. certbot | - If you like Certbot, please consider supporting our work by: certbot | certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate certbot | Donating to EFF: https://eff.org/donate-le certbot | certbot exited with code 0

      После добавления ваших сертификатов вы можете перейти к изменению конфигурации Nginx для использования SSL.

      Шаг 5 — Изменение конфигурации веб-сервера и определения службы

      Активация SSL в нашей конфигурации Nginx будет включать организацию перенаправления HTTP на HTTPS, указание расположения сертификата и ключей SSL и добавление параметров безопасности и заголовков.

      Поскольку вы будете воссоздавать службу webserver для включения этих нововведений, сейчас вы можете остановить ее работу:

      • docker-compose stop webserver

      Прежде чем мы самостоятельно изменим файл конфигурации, нам нужно предварительно получить рекомендуемые параметры безопасности Nginx от Certbot с помощью curl:

      • curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf

      Данная команда будет сохранять эти параметры в файле с именем options-ssl-nginx.conf, расположенном в директории nginx-conf.

      Затем удалите ранее созданный файл конфигурации Nginx:

      Откройте другую версию файла:

      • nano nginx-conf/nginx.conf

      Добавьте следующий код в файл для перенаправления HTTP на HTTPS и добавления учетных данных, протоколов и заголовков безопасности SSL. Обязательно замените example.com​​ на ваше доменное имя:

      ~/wordpress/nginx-conf/nginx.conf

      server {
              listen 80;
              listen [::]:80;
      
              server_name example.com www.example.com;
      
              location ~ /.well-known/acme-challenge {
                      allow all;
                      root /var/www/html;
              }
      
              location / {
                      rewrite ^ https://$host$request_uri? permanent;
              }
      }
      
      server {
              listen 443 ssl http2;
              listen [::]:443 ssl http2;
              server_name example.com www.example.com;
      
              index index.php index.html index.htm;
      
              root /var/www/html;
      
              server_tokens off;
      
              ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
              ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
      
              include /etc/nginx/conf.d/options-ssl-nginx.conf;
      
              add_header X-Frame-Options "SAMEORIGIN" always;
              add_header X-XSS-Protection "1; mode=block" always;
              add_header X-Content-Type-Options "nosniff" always;
              add_header Referrer-Policy "no-referrer-when-downgrade" always;
              add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
              # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
              # enable strict transport security only if you understand the implications
      
              location / {
                      try_files $uri $uri/ /index.php$is_args$args;
              }
      
              location ~ .php$ {
                      try_files $uri =404;
                      fastcgi_split_path_info ^(.+.php)(/.+)$;
                      fastcgi_pass wordpress:9000;
                      fastcgi_index index.php;
                      include fastcgi_params;
                      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                      fastcgi_param PATH_INFO $fastcgi_path_info;
              }
      
              location ~ /.ht {
                      deny all;
              }
      
              location = /favicon.ico {
                      log_not_found off; access_log off;
              }
              location = /robots.txt {
                      log_not_found off; access_log off; allow all;
              }
              location ~* .(css|gif|ico|jpeg|jpg|js|png)$ {
                      expires max;
                      log_not_found off;
              }
      }
      

      Блок сервера HTTP указывает webroot для запросов обновления Certbot в директории .well-known/acme-challenge. Также он содержит директиву перезаписи, которая перенаправляет запросы HTTP в корневую директорию HTTPS.

      Блок сервера HTTPS активирует ssl и http2. Дополнительную информацию о том, как выполняется итерация HTTP/2 в протоколах HTTP и какие преимущества это может дать для повышения производительности веб-сайта, см. во вводной части руководства по настройке Nginx с поддержкой HTTP/2 в Ubuntu 18.04.

      Этот блок также включает расположение наших сертификата SSL и ключа, а также рекомендованные параметры безопасности Certbot, которые мы сохранили в nginx-conf/options-ssl-nginx.conf.

      Кроме того, мы включили ряд заголовков безопасности, которые позволят нам получить оценки A на сайтах серверных тестов SSL Labs и Security Headers. Эти заголовки включают X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy и X-XSS-Protection. Заголовок HTTP Strict Transport Security (Строгая безопасность передачи информации по протоколу HTTP) закомментирован, активируйте этот элемент, только если вы понимаете возможные последствия и оценили его «предварительно загруженный» функционал.

      Наши директивы root и index также расположены в этом блоке, равно как и остальные блоки расположения WordPress, описанные в шаге 1.

      После завершения редактирования сохраните и закройте файл.

      Перед повторным созданием службы webserver вам потребуется добавить распределение порта 443 в определение службы webserver.

      Откройте ваш файл docker-compose.yml​​​:

      В определении службы webserver добавьте следующее распределение порта:

      ~/wordpress/docker-compose.yml

      ...
        webserver:
          depends_on:
            - wordpress
          image: nginx:1.15.12-alpine
          container_name: webserver
          restart: unless-stopped
          ports:
            - "80:80"
            - "443:443"
          volumes:
            - wordpress:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - app-network
      

      Файл docker-compose.yml будет выглядеть следующим образом после завершения настройки:

      ~/wordpress/docker-compose.yml

      version: '3'
      
      services:
        db:
          image: mysql:8.0
          container_name: db
          restart: unless-stopped
          env_file: .env
          environment:
            - MYSQL_DATABASE=wordpress
          volumes:
            - dbdata:/var/lib/mysql
          command: '--default-authentication-plugin=mysql_native_password'
          networks:
            - app-network
      
        wordpress:
          depends_on:
            - db
          image: wordpress:5.1.1-fpm-alpine
          container_name: wordpress
          restart: unless-stopped
          env_file: .env
          environment:
            - WORDPRESS_DB_HOST=db:3306
            - WORDPRESS_DB_USER=$MYSQL_USER
            - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
            - WORDPRESS_DB_NAME=wordpress
          volumes:
            - wordpress:/var/www/html
          networks:
            - app-network
      
        webserver:
          depends_on:
            - wordpress
          image: nginx:1.15.12-alpine
          container_name: webserver
          restart: unless-stopped
          ports:
            - "80:80"
            - "443:443"
          volumes:
            - wordpress:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
          networks:
            - app-network
      
        certbot:
          depends_on:
            - webserver
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - wordpress:/var/www/html
          command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
      
      volumes:
        certbot-etc:
        wordpress:
        dbdata:
      
      networks:
        app-network:
          driver: bridge  
      

      Сохраните и закройте файл после завершения редактирования.

      Повторно создайте службу webserver:

      • docker-compose up -d --force-recreate --no-deps webserver

      Проверьте ваши службы с помощью команды docker-compose ps:

      Вы должны получить результат, указывающий, что ваши службы db, wordpress и webserver запущены:

      Output

      Name Command State Ports ---------------------------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp wordpress docker-entrypoint.sh php-fpm Up 9000/tcp

      После запуска ваших контейнеров вы можете завершить процесс установки WordPress через веб-интерфейс.

      Шаг 6 — Завершение установки через веб-интерфейс

      После запуска контейнеров мы можем завершить установку через веб-интерфейс WordPress.

      В браузере перейдите на домен вашего сервера. Не забудьте заменить здесь example.com на ваше доменное имя:

      https://example.com
      

      Выберите язык, который вы хотите использовать:

      Средство выбор языка WordPress

      После нажатия Continue (Продолжить) вы перейдете на главную страницу настройки, где вам нужно будет выбрать имя вашего сайта и пользователя. Рекомендуется выбрать запоминающееся имя пользователя (не просто «admin») и надежный пароль. Вы можете использовать пароль, который генерирует WordPress автоматически, или задать собственный пароль.

      Наконец, вам нужно будет ввести ваш адрес электронной почты и указать, хотите ли вы, чтобы движки поисковых систем могли индексировать ваш сайт:

      Главная страница настройки WordPress

      После нажатия Install WordPress (Установить WordPress) внизу страницы на экране появится запрос выполнения входа:

      Экран входа WordPress

      После входа вы получите доступ к панели управления WordPress:

      Панель управления WordPress

      После завершения установки WordPress вы можете выполнить определенные действия, необходимые для гарантии того, что ваши сертификаты SSL будут обновляться автоматически.

      Шаг 7 — Обновление сертификатов

      Сертификаты Let’s Encrypt действительны в течение 90 дней, поэтому вам нужно будет настроить автоматический процесс обновления, чтобы гарантировать, что сертификаты не окажутся просроченными. Один из способов — создание задания с помощью утилиты планирования cron. В нашем случае мы настроим задание для cron с помощью скрипта, который будет обновлять наши сертификаты и перезагружать конфигурацию Nginx.

      Откройте скрипт под названием ssl_renew.sh:

      Добавьте следующий код в скрипт, чтобы обновить ваши сертификаты и перезагрузить конфигурацию веб-сервера. Не забудьте заменить приведенное в качестве примера имя пользователя своим именем пользователя:

      ~/wordpress/ssl_renew.sh

      #!/bin/bash
      
      COMPOSE="/usr/local/bin/docker-compose --no-ansi"
      DOCKER="/usr/bin/docker"
      
      cd /home/sammy/wordpress/
      $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
      $DOCKER system prune -af
      

      Данный скрипт привязывает двоичный код docker-compose для переменной COMPOSE и задает параметр --no-ansi, который запускает команды docker-compose без управляющих символов ANSI. Затем он делает то же самое с двоичным файлом docker. В заключение он меняет каталог проекта на ~/wordpress и запускает следующие команды docker-compose:

      • docker-compose run: данный параметр запускает контейнер certbot и переопределяет параметр command, указанный в определении службы certbot. Вместо использования субкоманды certonly мы используем здесь субкоманду renew, которая будет обновлять сертификаты, срок действия которых близок к окончанию. Мы включили параметр --dry-run, чтобы протестировать наш скрипт.
      • docker-compose kill: данный параметр отправляет сигнал SIGHUP контейнеру webserver для перезагрузки конфигурации Nginx. Дополнительную информацию об использовании этого процесса для перезагрузки конфигурации Nginx см. в этой публикации блога Docker, посвященной развертыванию официального образа Nginx с помощью Docker.

      После этого он выполняет команду docker system prune для удаления всех неиспользуемых контейнеров и образов.

      Закройте файл после завершения редактирования. Сделайте его исполняемым:

      Далее откройте root файл crontab для запуска скрипта обновления с заданным интервалом:

      Если вы в первый раз редактируете этот файл, вам будет предложено выбрать редактор:

      Output

      no crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano <---- easiest 2. /usr/bin/vim.basic 3. /usr/bin/vim.tiny 4. /bin/ed Choose 1-4 [1]: ...

      Добавьте внизу файла следующую строку:

      crontab

      ...
      */5 * * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
      

      В результате будет установлен интервал в 5 минут для выполнения работы, и вы можете проверить, работает ли запрос обновления так, как предполагается. Также мы создали файл журнала, cron.log, чтобы записывать соответствующий вывод выполнения задания.

      Через 5 минут проверьте cron.log, чтобы убедиться, что запрос обновления выполнен успешно:

      • tail -f /var/log/cron.log

      Вы должны увидеть вывод, подтверждающий успешное обновление:

      Output

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/example.com/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

      Теперь вы можете изменить файл crontab для настройки ежедневного интервала. Чтобы запускать скрипт каждый день в полдень, например, вы должны изменить последнюю строку файла, которая должна выглядеть следующим образом:

      crontab

      ...
      0 12 * * * /home/sammy/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
      

      Также вы можете изменить параметр --dry-run из скрипта ssl_renew.sh:

      ~/wordpress/ssl_renew.sh

      #!/bin/bash
      
      COMPOSE="/usr/local/bin/docker-compose --no-ansi"
      DOCKER="/usr/bin/docker"
      
      cd /home/sammy/wordpress/
      $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
      $DOCKER system prune -af
      

      Ваше задание cron гарантирует, что ваши сертификаты Let’s Encrypt не окажутся устаревшими, обновляя их в случае истечения срока действия. Также вы можете настроить замену журнала с помощью утилиты Logrotate, которая будет выполнять ротацию и сжатие файлов журнала.

      Заключение

      В этом руководстве вы использовали Docker Compose для создания установки WordPress с веб-сервером Nginx. В рамках этого рабочего процесса вы получили сертификаты TLS/SSL для домена, который вы хотите подключить к вашему сайту WordPress. Кроме того, вы создали задание cron для обновления этих сертификатов при необходимости.

      В качестве дополнительных мер по повышению производительности сайта и создания запаса мощности, вы можете ознакомиться со следующими статьями, посвященными передаче и поддержке активов WordPress:

      Если вы заинтересованы в изучении контейнеризированного рабочего процесса с помощью Kubernetes, вы также можете ознакомиться со следующими материалами:



      Source link

      Обеспечение безопасности контейнеризованного приложения Node.js с помощью Nginx, Let’s Encrypt и Docker Compose


      Введение

      Существует множество способов повышения гибкости и безопасности приложения Node.js. Использование обратного прокси-сервера, например Nginx, позволяет равномерно распределять запросы, кэшировать статический контент и реализовать протокол Transport Layer Security (TLS). Активация шифрования HTTPS на сервере гарантирует, что исходящие и входящие коммуникации вашего приложения останутся безопасными.

      Реализация обратного прокси с TLS/SSL в контейнерах охватывает различный набор процедур, подразумевающих работу непосредственно в операционной системе хоста. Например, если вы получали сертификаты от Let’s Encrypt для приложения, запущенного на сервере, то должны были установить требуемое программное обеспечение непосредственно на вашем хосте. Контейнеры позволяют воспользоваться другим методом. С помощью Docker Compose вы можете создавать контейнеры для вашего приложения, веб-сервера и клиента Certbot, которые позволят вам получить сертификаты. Выполнив следующие шаги, вы можете воспользоваться преимуществами модульности и портативности контейнеризированного рабочего процесса.

      В этом руководстве вы развернете приложение Node.js с обратным прокси Nginx с помощью Docker Compose. Вы получите сертификаты TLS/SSL для домена, связанного с вашим приложением, а также убедитесь, что оно получает высокую оценку безопасности от SSL Labs. Наконец, вы настроите задание cron для обновления ваших сертификатов, чтобы ваш домен оставался защищенным.

      Предварительные требования

      Для данного обучающего модуля вам потребуется следующее:

      • Сервер Ubuntu 18.04, пользователь без прав root с привилегиями sudo и активный брандмауэр. Дополнительную информацию о настройке этих параметров см. в руководстве по первоначальной настройке сервера.
      • Docker и Docker Compose, установленные на вашем сервере. Инструкции по установке Docker см. в шагах 1 и 2 руководства Установка и использование Docker в Ubuntu 18.04. Дополнительную информацию по установке Compose см. в шаге 1 руководства Установка Docker Compose в Ubuntu 18.04.
      • Зарегистрированное доменное имя. В этом обучающем руководстве мы будем использовать example.com. Вы можете получить бесплатный домен на Freenom или зарегистрировать доменное имя по вашему выбору.
      • На вашем сервере должны быть настроены обе нижеследующие записи DNS. Вы можете воспользоваться введением в работу с DigitalOcean DNS, чтобы получить подробную информацию о добавлении доменов в учетную запись DigitalOcean, если вы используете этот способ:

        • Запись A, где example.com указывает на публичный IP-адрес вашего сервера.
        • Запись A, где www.example.com указывает на публичный IP-адрес вашего сервера.

      Шаг 1 — Клонирование и тестирование приложения Node

      В качестве первого шага мы клонируем репозиторий с кодом приложения Node, который включает файл Dockerfile, который мы будем использовать для сборки образа нашего приложения с помощью Compose. Мы можем протестировать приложение, выполнив его сборку и запустив его с помощью команды docker run без использования обратного прокси или SSL.

      В корневой директории пользователя без прав root клонируйте репозиторий nodejs-image-demo из учетной записи DigitalOcean на GitHub. Этот репозиторий содержит код настройки, описанной в руководстве Сборка приложения Node.js с помощью Docker.

      Клонируйте репозиторий в директорию с именем node_project:

      • git clone https://github.com/do-community/nodejs-image-demo.git node_project

      Перейдите в директорию node_project:

      В этой директории имеется файл Dockerfile, содержащий инструкции по сборке приложения Node с помощью образа Docker node:10 и содержимое директории вашего текущего проекта. Вы можете посмотреть содержимое файла Dockerfile, введя следующую команду:

      Output

      FROM node:10-alpine RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY package*.json ./ USER node RUN npm install COPY --chown=node:node . . EXPOSE 8080 CMD [ "node", "app.js" ]

      Эти инструкции позволят собрать образ Node, скопировав код проекта из текущей директории в контейнер и установив зависимости с помощью npm install. Также они помогут воспользоваться преимуществами кэширования и слоев образа Docker, отделив копию package.json и package-lock.json​​​, содержащую список зависимостей проекта, от копии остального кода. Наконец, инструкции указывают, что контейнер будет запускаться в качестве пользователя node без прав root с соответствующими разрешениями, заданными для кода приложения и директорий node_modules.

      Дополнительную информацию о рекомендуемых практиках работы с Dockerfile и образом Node см. в шаге 3 руководства Сборка приложения Node.js с помощью Docker.

      Чтобы протестировать приложение без SSL, вы можете выполнить сборку и создать метку с помощью команды docker build и флага -t. Мы назовем образ node-demo​​​, но вы можете указать другое имя:

      • docker build -t node-demo .

      После завершения процесса сборки вы можете вывести список образов с помощью команды docker images:

      Вы увидите следующий вывод, подтверждающий сборку образа приложения:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE node-demo latest 23961524051d 7 seconds ago 73MB node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MB

      Затем создайте контейнер с помощью команды docker run. Мы добавим к этой команде три флага:

      • -p: публикует порт контейнера и сопоставляет его с портом хоста. Мы используем порт 80 на нашем хосте, но вы можете использовать любой другой порт, если этот порт занят каким-то другим процессом. Дополнительную информацию по принципам привязки портов можно найти в соответствующей документации Docker.
      • -d: запускает контейнер в фоновом режиме.
      • --name: позволяет присвоить контейнеру запоминающееся имя.

      Запустите следующую команду для сборки контейнера:

      • docker run --name node-demo -p 80:8080 -d node-demo

      Просмотрите запущенные контейнеры с помощью команды docker ps:

      Вы увидите вывод, подтверждающий, что контейнер вашего приложения запущен:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo

      Теперь вы можете посетить ваш домен, чтобы протестировать настройку: http://example.com. Обязательно замените example.com​​ на ваше доменное имя. Ваше приложение отобразит следующую начальную страницу:

      Начальная страница приложения

      Теперь, когда вы протестировали приложение, вы можете остановить контейнер и удалить образы. Воспользуйтесь docker ps снова, чтобы получить идентификатор CONTAINER ID:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demo

      Остановите контейнер с помощью команды docker stop. Обязательно замените указанный здесь CONTAINER ID на CONTAINER ID вашего приложения:

      Теперь вы можете удалить остановленный контейнер и все образы, включая неиспользуемые и недействительные образы, с помощью команды docker system prune и флага -a:

      Введите y в диалоговом окне, чтобы подтвердить удаление остановленного контейнера и образов. Помните, что при этом также будет удален кэш вашей сборки.

      Когда образ вашего приложения будет протестирован, вы можете перейти к сборке остальной части настройки с помощью Docker Compose.

      Шаг 2 — Настройка конфигурации веб-сервера

      После добавления нашего приложения Dockerfile мы можем создать файл конфигурации для запуска контейнера Nginx. Мы запустим минимальную конфигурацию, которая будет включать наше доменное имя, корневую директорию документа, информацию о прокси и блок расположения для перенаправления запросов Certbot в директорию .well-known, где будет размещаться временный файл для подтверждения того, что DNS для нашего домена будет использоваться на сервере.

      Во-первых, создайте директорию в текущей директории проекта для файла конфигурации:

      Откройте файл с помощью nano или своего любимого редактора:

      • nano nginx-conf/nginx.conf

      Добавьте следующий серверный блок для запросов пользователя прокси в контейнер приложения Node и для перенаправления запросов Certbot в директорию .well-known. Обязательно замените example.com на ваше доменное имя.

      ~/node_project/nginx-conf/nginx.conf

      server {
              listen 80;
              listen [::]:80;
      
              root /var/www/html;
              index index.html index.htm index.nginx-debian.html;
      
              server_name example.com www.example.com;
      
              location / {
                      proxy_pass http://nodejs:8080;
              }
      
              location ~ /.well-known/acme-challenge {
                      allow all;
                      root /var/www/html;
              }
      }
      

      Этот серверный блок позволит запустить контейнер Nginx в качестве обратного прокси-сервера, который будет передавать запросы контейнеру приложения Node. Также это позволит нам использовать плагин webroot для Certbot, чтобы получить сертификаты для нашего домена. Работа плагина основана на методе валидации HTTP-01, который использует запрос HTTP, чтобы доказать, что Certbot может получить доступ к ресурсам с сервера, который отвечает на заданное доменное имя.

      После завершения редактирования сохраните и закройте файл. Чтобы узнать больше о сервере Nginx и алгоритмах блока расположения, ознакомьтесь со статьей Знакомство с сервером Nginx и алгоритмами выбора блоков расположения.

      После добавления данных конфигурации веб-сервера мы можем перейти к созданию файла docker-compose.yml, который позволит нам создавать службы приложения и контейнер Certbot, который мы будем использовать для получения сертификатов.

      Шаг 3 — Создание файла Docker Compose

      Файл docker-compose.yml будет определять наши службы, включая приложение Node и веб-сервер. В нем будут указаны такие данные, как имена томов, которые имеют критическое значение для обмена учетными данными SSL между контейнерами, а также информацией о сети и порте. Также он позволяет указать конкретные команды, которые будут запускаться при создании контейнеров. Этот файл является центральным ресурсом, который будет определять, как будет организована совместная работа наших служб.

      Откройте файл в текущей директории:

      Определите службу приложения:

      ~/node_project/docker-compose.yml

      version: '3'
      
      services:
        nodejs:
          build:
            context: .
            dockerfile: Dockerfile
          image: nodejs
          container_name: nodejs
          restart: unless-stopped
      

      Определение службы nodejs включает следующее:

      • build: это определение параметров конфигурации, включая context и dockerfile, которые будут применяться при создании образа приложения Compose. Если вы хотите использовать существующий образ из реестра, например из Docker Hub, вы можете использовать инструкцию image с информацией об имени пользователя, репозитория и теге образа.
      • context: определение контекста сборки для сборки образа приложения. В нашем случае это текущая директория проекта.
      • dockerfile: данный параметр указывает файл Dockerfile, который Compose будет использоваться для сборки, т. е. файл Dockerfile, который мы рассматривали на шаге 1.
      • image, container_name: эти параметры присваивают имена для образа и контейнера.
      • restart: данный параметр определяет политику перезапуска. По умолчанию установлено значение no, но мы задали значение, согласно которому контейнер будет перезапускаться, пока не будет закрыт.

      Обратите внимание, что мы не будем использовать связанные монтируемые образы в данной службе, поскольку главное внимание в нашей настройке уделяется развертыванию, а не разработке. Дополнительную информацию см. в документации Docker по связанным монтируемым образам и томам.

      Чтобы активировать коммуникацию между контейнерами приложения и веб-сервера, мы также добавим мостовую сеть app-network под определением перезапуска:

      ~/node_project/docker-compose.yml

      services:
        nodejs:
      ...
          networks:
            - app-network
      

      Определяемая пользователем мостовая сеть, наподобие нашей, позволяет осуществлять связь между контейнерами на одном демон-хосте Docker. Это позволяет организовать трафик и коммуникации внутри приложения, поскольку она открывает все порты между контейнерами в одной мостовой сети, скрывая все порты от внешнего мира. Таким образом, у вас появляется возможность выбора, какие порты вам нужно открыть для ваших служб фронтэнда.

      Далее нужно определить службу webserver:

      ~/node_project/docker-compose.yml

      ...
       webserver:
          image: nginx:mainline-alpine
          container_name: webserver
          restart: unless-stopped
          ports:
            - "80:80"
          volumes:
            - web-root:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
            - certbot-var:/var/lib/letsencrypt
          depends_on:
            - nodejs
          networks:
            - app-network
      

      Некоторые настройки, которые мы определили для службы nodejs, остаются без изменений, но мы внесем следующие изменения:

      • image: данный элемент указывает Compose на необходимость извлечения последнего образа Nginx на базе Alpine из Docker Hub. Дополнительную информацию о образах alpine см. в шаге 3 руководства Сборка приложения Node.js с помощью Docker.
      • ports: данный элемент использует порт 80 для активации параметров конфигурации, которые мы определили в конфигурации Nginx.

      Также мы указали следующие имена томов и связанных монтируемых образов:

      • web-root:/var/www/html: этот элемент будет добавлять статические активы нашего сайта, скопированные в том web-root, в директорию /var/www/html на контейнере.
      • ./nginx-conf:/etc/nginx/conf.d: этот элемент будет монтировать директорию конфигурации Nginx на хост в соответствующую директорию в контейнере, гарантируя, что любые изменения, которые мы вносим в файлы на хосте, будут отражены в контейнере.
      • certbot-etc:/etc/letsencrypt: этот элемент будет монтировать соответствующие сертификаты и ключи Let’s Encrypt для нашего домена в соответствующую директорию контейнера.
      • certbot-var:/var/lib/letsencrypt: этот элемент монтирует используемую по умолчанию рабочую директорию Let’s Encrypt в соответствующую директорию контейнера.

      Далее добавьте параметры конфигурации для контейнера certbot. Обязательно замените домен и информацию об электронной почте на ваши имя домена и электронную почту:

      ~/node_project/docker-compose.yml

      ...
        certbot:
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - certbot-var:/var/lib/letsencrypt
            - web-root:/var/www/html
          depends_on:
            - webserver
          command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com  -d www.example.com
      

      Это определение попросит Compose извлекать образ certbot/certbot из Docker Hub. Также оно использует имена томов для обмена ресурсами с контейнером Nginx, включая доменные сертификаты и ключ в certbot-etc, рабочую директорию Let’s Encrypt в certbot-var и код приложения в web-root.

      Мы использовали depends_on, чтобы указать, что контейнер certbot следует запускать только после запуска службы webserver.

      Также мы включили параметр command, который указывает команду, которая будет выполняться при запуске контейнера. Он включает субкоманду certonly со следующими элементами:

      • --webroot: данный элемент говорит Certbot о необходимости использования плагина webroot для размещения файлов в папке webroot для аутентификации.
      • --webroot-path: данный элемент указывает путь директории webroot.
      • --email: предпочитаемый адрес электронной почты для регистрации и восстановления.
      • --agree-tos: данный элемент указывает, что вы принимаете Соглашение о подписке ACME.
      • --no-eff-email: данный элемент указывает Certbot, что вы не хотите делиться адресом электронной почты с Electronic Frontier Foundation​​​ (EFF). Вы можете пропустить этот элемент.
      • --staging: данный элемент говорит Certbot, что вы хотите использовать промежуточную среду Let’s Encrypt для получения тестовых сертификатов. При использовании этого параметра вы можете протестировать параметры конфигурации и избежать возможных пределов для запросов домена. Дополнительную информацию об этих предельных значениях см. в документации по ограничениям скорости Let’s Encrypt.
      • -d: данный элемент позволяет указать доменные имена, которые вы хотите использовать для вашего запроса. В нашем случае мы включили example.com и www.example.com. Обязательно замените эти данные на ваш домен.

      В качестве заключительного шага добавьте определения тома и сети. Обязательно замените имя пользователя на имя вашего пользователя без прав root:

      ~/node_project/docker-compose.yml

      ...
      volumes:
        certbot-etc:
        certbot-var:
        web-root:
          driver: local
          driver_opts:
            type: none
            device: /home/sammy/node_project/views/
            o: bind
      
      networks:
        app-network:
          driver: bridge
      

      Наши имена томов включают наш сертификат Certbot и тома рабочей директории, а также том для статичных активов нашего сайта, web-root. В большинстве случаев для томов Docker по умолчанию используется драйвер local, который в Linux принимает параметры, аналогичные команде mount. Благодаря этому мы можем указать список параметров для драйверов с помощью команды driver_opts, которая монтирует директорию views на хосте, содержащем статические активы нашего приложения, на том во время исполнения. Содержимое директории затем может передаваться между контейнерами. Дополнительную информацию о содержании директории views см. в шаге 2 руководства Сборка приложения Node.js с помощью Docker.

      Файл docker-compose.yml будет выглядеть следующим образом после завершения настройки:

      ~/node_project/docker-compose.yml

      version: '3'
      
      services:
        nodejs:
          build:
            context: .
            dockerfile: Dockerfile
          image: nodejs
          container_name: nodejs
          restart: unless-stopped
          networks:
            - app-network
      
        webserver:
          image: nginx:mainline-alpine
          container_name: webserver
          restart: unless-stopped
          ports:
            - "80:80"
          volumes:
            - web-root:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
            - certbot-var:/var/lib/letsencrypt
          depends_on:
            - nodejs
          networks:
            - app-network
      
        certbot:
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - certbot-var:/var/lib/letsencrypt
            - web-root:/var/www/html
          depends_on:
            - webserver
          command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --staging -d example.com  -d www.example.com
      
      volumes:
        certbot-etc:
        certbot-var:
        web-root:
          driver: local
          driver_opts:
            type: none
            device: /home/sammy/node_project/views/
            o: bind
      
      networks:
        app-network:
          driver: bridge  
      

      После добавления определений службы вы можете запустить контейнеры и протестировать запросы сертификата.

      Шаг 4 — Получение сертификатов и учетных данных SSL

      Мы можем запустить наши контейнеры с помощью команды docker-compose up, которая будет создавать и запускать наши контейнеры и службы в указанном нами порядке. Если наши запросы доменов будут выполнены успешно, мы увидим корректный статус выхода в нашем выводе и нужные сертификаты, установленные в папке /etc/letsencrypt/live на контейнере webserver.

      Создайте службы с помощью команды docker-compose up и флага -d, которые будут запускать контейнеры nodejs и webserver в фоновом режиме:

      Вы увидите вывод, подтверждающий, что ваши службы были успешно созданы:

      Output

      Creating nodejs ... done Creating webserver ... done Creating certbot ... done

      С помощью docker-compose ps проверьте статус ваших служб:

      Если все будет выполнено успешно, ваши службы nodejs и webserver должны иметь статус Up, а работа контейнера certbot будет завершена с сообщением о статусе 0:

      Output

      Name Command State Ports ------------------------------------------------------------------------ certbot certbot certonly --webroot ... Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp

      Если вы увидите любое значение, кроме Up в столбце State для служб nodejs и webserver, или любое сообщение о статусе выхода, отличающееся от 0, для контейнера certbot, проверьте журналы службы с помощью команды docker-compose logs:

      • docker-compose logs service_name

      Теперь вы можете убедиться, что ваши учетные данные были смонтированы в контейнер webserver с помощью команды docker-compose exec:

      • docker-compose exec webserver ls -la /etc/letsencrypt/live

      Если запрос будет выполнен успешно, вы увидите следующий вывод:

      Output

      total 16 drwx------ 3 root root 4096 Dec 23 16:48 . drwxr-xr-x 9 root root 4096 Dec 23 16:48 .. -rw-r--r-- 1 root root 740 Dec 23 16:48 README drwxr-xr-x 2 root root 4096 Dec 23 16:48 example.com

      Теперь, когда вы убедились, что ваш запрос будет выполнен успешно, вы можете изменить определение службы certbot для удаления флага --staging.

      Откройте docker-compose.yml:

      Найдите раздел файла с определением службы certbot и замените флаг --staging в параметрах command на флаг --force-renewal, который будет указывать Certbot, что вы хотите запросить новый сертификат с теми же доменами, что и в уже существующем сертификате. Определение службы certbot должно выглядеть следующим образом:

      ~/node_project/docker-compose.yml

      ...
        certbot:
          image: certbot/certbot
          container_name: certbot
          volumes:
            - certbot-etc:/etc/letsencrypt
            - certbot-var:/var/lib/letsencrypt
            - web-root:/var/www/html
          depends_on:
            - webserver
          command: certonly --webroot --webroot-path=/var/www/html --email [email protected] --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com
      ...
      

      Теперь вы можете запустить docker-compose up для воссоздания контейнера certbot и соответствующих томов. Также мы будем использовать параметр --no-deps, чтобы сообщить Compose о том, что можно пропустить запуск службы webserver, поскольку она уже запущена:

      • docker-compose up --force-recreate --no-deps certbot

      Вы увидите вывод, указывающий, что запрос сертификата выполнен успешно:

      Output

      certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/example.com/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/example.com/privkey.pem certbot | Your cert will expire on 2019-03-26. To obtain a new or tweaked certbot | version of this certificate in the future, simply run certbot certbot | again. To non-interactively renew *all* of your certificates, run certbot | "certbot renew" certbot | - Your account credentials have been saved in your Certbot certbot | configuration directory at /etc/letsencrypt. You should make a certbot | secure backup of this folder now. This configuration directory will certbot | also contain certificates and private keys obtained by Certbot so certbot | making regular backups of this folder is ideal. certbot | - If you like Certbot, please consider supporting our work by: certbot | certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate certbot | Donating to EFF: https://eff.org/donate-le certbot | certbot exited with code 0

      После добавления ваших сертификатов вы можете перейти к изменению конфигурации Nginx для использования SSL.

      Шаг 5 — Изменение конфигурации веб-сервера и определения службы

      Активация SSL в нашей конфигурации Nginx будет подразумевать добавление перенаправления HTTP на HTTPS и указание расположения сертификата и ключей SSL. Также нам нужно будет указать нашу группу Diffie-Hellman, которую мы будем использовать для Совершенной прямой секретности.

      Поскольку вы будете воссоздавать службу webserver для включения этих нововведений, сейчас вы можете остановить ее работу:

      • docker-compose stop webserver

      Далее создайте директорию в текущей директории проекта для вашего ключа Diffie-Hellman:

      Сгенерируйте ключ с помощью команды openssl:

      • sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048

      Процесс генерации ключа может занять несколько минут.

      Чтобы добавить данные о Diffie-Hellman и SSL в конфигурацию Nginx, первым делом удалите ранее созданный файл конфигурации Nginx:

      Откройте другую версию файла:

      • nano nginx-conf/nginx.conf

      Добавьте следующий код в файл для перенаправления HTTP на HTTPS и добавления учетных данных, протоколов и заголовков безопасности SSL. Обязательно замените example.com​​ на ваше доменное имя:

      ~/node_project/nginx-conf/nginx.conf

      
      server {
              listen 80;
              listen [::]:80;
              server_name example.com www.example.com;
      
              location ~ /.well-known/acme-challenge {
                allow all;
                root /var/www/html;
              }
      
              location / {
                      rewrite ^ https://$host$request_uri? permanent;
              }
      }
      
      server {
              listen 443 ssl http2;
              listen [::]:443 ssl http2;
              server_name example.com www.example.com;
      
              server_tokens off;
      
              ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
              ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
      
              ssl_buffer_size 8k;
      
              ssl_dhparam /etc/ssl/certs/dhparam-2048.pem;
      
              ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
              ssl_prefer_server_ciphers on;
      
              ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
      
              ssl_ecdh_curve secp384r1;
              ssl_session_tickets off;
      
              ssl_stapling on;
              ssl_stapling_verify on;
              resolver 8.8.8.8;
      
              location / {
                      try_files $uri @nodejs;
              }
      
              location @nodejs {
                      proxy_pass http://nodejs:8080;
                      add_header X-Frame-Options "SAMEORIGIN" always;
                      add_header X-XSS-Protection "1; mode=block" always;
                      add_header X-Content-Type-Options "nosniff" always;
                      add_header Referrer-Policy "no-referrer-when-downgrade" always;
                      add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
                      # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
                      # enable strict transport security only if you understand the implications
              }
      
              root /var/www/html;
              index index.html index.htm index.nginx-debian.html;
      }
      

      Блок сервера HTTP указывает webroot для запросов обновления Certbot в директории .well-known/acme-challenge. Также он содержит директиву перезаписи, которая перенаправляет запросы HTTP в корневую директорию HTTPS.

      Блок сервера HTTPS активирует ssl и http2. Дополнительную информацию о том, как выполняется итерация HTTP/2 в протоколах HTTP и какие преимущества это может дать для повышения производительности веб-сайта, см. во вводной части руководства по настройке Nginx с поддержкой HTTP/2 в Ubuntu 18.04. Этот блок также включает ряд параметров, гарантирующих, что вы используете самые актуальные протоколы и шифры SSL, а также то, что расширение OCSP stapling будет активировано. Расширение OCSP stapling позволяет вам обеспечивать ответ с привязкой по времени от издателя сертификата во время первоначального TLS-рукопожатия, что позволяет ускорить процесс аутентификации.

      Блок также указывает расположение ваших учетных данных и ключей SSL и Diffie-Hellman.

      Наконец, мы переместили информацию о передаче прокси, включая блок расположения с директивой try_files, указав запросы для нашего альтернативного контейнера приложения Node.js и блок расположения для этой альтернативы, которые включают заголовки безопасности, позволяющие нам получить оценки А для таких вещей, как серверные тестовые сайты SSL Labs и Security Headers. Эти заголовки включают X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy и X-XSS-Protection. Заголовок HTTP Strict Transport Security (Строгая безопасность передачи информации по протоколу HTTP) закомментирован, активируйте этот элемент, только если вы понимаете возможные последствия и оценили его “предварительно загруженный” функционал.

      После завершения редактирования сохраните и закройте файл.

      Прежде чем воссоздать службу webserver, вам нужно добавить несколько элементов в определение службы в файл docker-compose.yml, включая соответствующую информацию о порте для HTTPS и определение тома Diffie-Hellman.

      Откройте файл:

      В определении службы webserver добавьте следующее распределение портов и том с именем dhparam:

      ~/node_project/docker-compose.yml

      ...
       webserver:
          image: nginx:latest
          container_name: webserver
          restart: unless-stopped
          ports:
            - "80:80"
            - "443:443"
          volumes:
            - web-root:/var/www/html
            - ./nginx-conf:/etc/nginx/conf.d
            - certbot-etc:/etc/letsencrypt
            - certbot-var:/var/lib/letsencrypt
            - dhparam:/etc/ssl/certs
          depends_on:
            - nodejs
          networks:
            - app-network
      

      Далее добавьте том dhparam в определения ваших томов:

      ~/node_project/docker-compose.yml

      ...
      volumes:
        ...
        dhparam:
          driver: local
          driver_opts:
            type: none
            device: /home/sammy/node_project/dhparam/
            o: bind
      

      Как и в случае с томом web-root, том dhparam будет монтировать ключ Diffie-Hellman, хранящийся на хосте, в контейнер webserver.

      Сохраните и закройте файл после завершения редактирования.

      Повторно создайте службу webserver:

      • docker-compose up -d --force-recreate --no-deps webserver

      Проверьте ваши службы с помощью команды docker-compose ps:

      Вы должны увидеть вывод, указывающий, что ваши службы nodejs и webserver запущены:

      Output

      Name Command State Ports ---------------------------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

      Наконец, вы можете посетить ваш домен, чтобы убедиться, что все работает ожидаемым образом. Перейдите в браузере по адресу https://example.com, заменив example.com на имя вашего домена. Вы увидите следующую начальную страницу:

      Начальная страница приложения

      Также вы должны увидеть значок замка в индикаторе безопасности браузера. При желании вы можете перейти к начальной странице теста сервера SSL Labs или начальной странице теста сервера Security Headers. Параметры конфигурации, которые мы использовали, должны обеспечить получение оценки А для вашего сайта в обоих тестах.

      Шаг 6 — Обновление сертификатов

      Сертификаты Let’s Encrypt действительны в течение 90 дней, поэтому вам нужно будет настроить автоматический процесс обновления, чтобы гарантировать, что сертификаты не окажутся просроченными. Один из способов — создание задания с помощью утилиты планирования cron. В нашем случае мы настроим задание для cron с помощью скрипта, который будет обновлять наши сертификаты и перезагружать конфигурацию Nginx.

      Откройте скрипт с именем ssl_renew.sh в директории проекта:

      Добавьте следующий код в скрипт, чтобы обновить ваши сертификаты и перезагрузить конфигурацию веб-сервера:

      ~/node_project/ssl_renew.sh

      #!/bin/bash
      
      COMPOSE="/usr/local/bin/docker-compose --no-ansi"
      DOCKER="/usr/bin/docker"
      
      cd /home/sammy/node_project/
      $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
      $DOCKER system prune -af
      

      Данный скрипт привязывает двоичный код docker-compose для переменной COMPOSE и задает параметр --no-ansi, который запускает команды docker-compose без управляющих символов ANSI. Затем он делает то же самое с двоичным файлом docker. В заключение он меняет директорию проекта на ~/node_project и запускает следующие команды docker-compose:

      • docker-compose run: данный параметр запускает контейнер certbot и переопределяет параметр command, указанный в определении службы certbot. Вместо использования субкоманды certonly мы используем здесь субкоманду renew, которая будет обновлять сертификаты, срок действия которых близок к окончанию. Мы включили параметр --dry-run, чтобы протестировать наш скрипт.
      • docker-compose kill: данный параметр отправляет сигнал SIGHUP контейнеру webserver для перезагрузки конфигурации Nginx. Дополнительную информацию об использовании этого процесса для перезагрузки конфигурации Nginx см. в этой публикации блога Docker, посвященной развертыванию официального образа Nginx с помощью Docker.

      После этого он выполняет команду docker system prune для удаления всех неиспользуемых контейнеров и образов.

      Закройте файл после завершения редактирования. Сделайте его исполняемым:

      Далее откройте root файл crontab для запуска скрипта обновления с заданным интервалом:

      Если вы в первый раз редактируете этот файл, вам будет предложено выбрать редактор:

      crontab

      no crontab for root - using an empty one
      Select an editor.  To change later, run 'select-editor'.
        1. /bin/ed
        2. /bin/nano        <---- easiest
        3. /usr/bin/vim.basic
        4. /usr/bin/vim.tiny
      Choose 1-4 [2]:
      ...
      

      Добавьте внизу файла следующую строку:

      crontab

      ...
      */5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
      

      В результате будет установлен интервал в 5 минут для выполнения работы, и вы можете проверить, работает ли запрос обновления так, как предполагается. Также мы создали файл журнала, cron.log, чтобы записывать соответствующий вывод выполнения задания.

      Через 5 минут проверьте cron.log, чтобы убедиться, что запрос обновления выполнен успешно:

      • tail -f /var/log/cron.log

      Вы должны увидеть вывод, подтверждающий успешное обновление:

      Output

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/example.com/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Killing webserver ... done

      Теперь вы можете изменить файл crontab для настройки ежедневного интервала. Чтобы запускать скрипт каждый день в полдень, например, вы должны изменить последнюю строку файла, которая должна выглядеть следующим образом:

      crontab

      ...
      0 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
      

      Также вы можете изменить параметр --dry-run из скрипта ssl_renew.sh:

      ~/node_project/ssl_renew.sh

      #!/bin/bash
      
      COMPOSE="/usr/local/bin/docker-compose --no-ansi"
      DOCKER="/usr/bin/docker"
      
      cd /home/sammy/node_project/
      $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
      $DOCKER system prune -af
      

      Ваше задание cron гарантирует, что ваши сертификаты Let’s Encrypt не окажутся устаревшими, обновляя их в случае истечения срока действия. Также вы можете настроить замену журнала с помощью утилиты Logrotate, которая будет выполнять ротацию и сжатие файлов журнала.

      Заключение

      Вы использовали контейнеры для настройки и запуска приложения Node с обратным прокси Nginx. Также вы обеспечили защиту SSL-сертификатов для домена приложения и настроили задание cron для обновления этих сертификатов при необходимости.

      Если вы хотите узнать больше о плагинах Let’s Encrypt, ознакомьтесь со статьями, посвященными использованию плагина Nginx или автономного плагина.

      Также вы можете узнать больше о Docker Compose, изучив следующие ресурсы:

      Документация Compose также может служить отличным источником информации о приложениях с несколькими контейнерами.



      Source link

      Создание приложения Node.js с помощью Docker


      Введение

      Платформа Docker позволяет разработчикам упаковывать и запускать приложения как контейнеры. Контейнер — это изолированный процесс, выполняемый в общей операционной системе, и представляющий из себя облегченную альтернативу виртуальным машинам. Хотя концепция контейнеров существует уже давно, обеспечиваемые ими преимущества изоляции процессов и стандартизации среды становятся все более важными по мере того, как все больше разработчиков начинают использовать распределенные архитектуры приложений.

      При создании и масштабировании приложений Docker вначале обычно создается образ приложения, который можно запустить в контейнере. Образ включает код приложения, библиотеки, файлы конфигурации, переменные среды и исполняемый модуль. Благодаря использованию образа среда в контейнере стандартизирована и содержит только то, что необходимо для сборки и выполнения приложения.

      В этом обучающем модуле вы создадите образ приложения для статического сайта, использующего систему Express и Bootstrap. Затем вы построите контейнер с этим образом и разместите его в Docker Hub для будущего использования. Наконец, вы извлечете сохраненный образ из хранилища Docker Hub и построите другой контейнер, продемонстрировав возможность воссоздания и масштабирования вашего приложения.

      Предварительные требования

      Для данного обучающего модуля вам потребуется следующее:

      Шаг 1 — Установка зависимостей вашего приложения

      Чтобы создать образ, нужно сначала выполнить сборку файлов приложения, а затем скопировать их в контейнер. Эти файлы будут включать статический контент, код и зависимости вашего приложения.

      Создайте для вашего проекта каталог в начальном каталоге пользователя, не являющегося пользователем root. Мы назовем наш проект node_project, но вы можете заменить это название на другое:

      Перейдите в этот каталог:

      Это будет корневой каталог проекта.

      Далее создайте файл package.json с зависимостями пакета и другой идентификационной информацией. Откройте файл с помощью nano или своего любимого редактора:

      Добавьте следующую информацию по проекту, включая его название, автора, лицензию, входную точку и зависимости. Обязательно замените данные автора собственным именем и контактными данными:

      ~/node_project/package.json

      {
        "name": "nodejs-image-demo",
        "version": "1.0.0",
        "description": "nodejs image demo",
        "author": "Sammy the Shark <[email protected]>",
        "license": "MIT",
        "main": "app.js",
        "keywords": [
          "nodejs",
          "bootstrap",
          "express"
        ],
        "dependencies": {
          "express": "^4.16.4"
        }
      }
      

      Файл содержит название проекта, автора и лицензию, по которой он распространяется. Npm рекомендует использовать краткие и содержательные названия проектов и избегать использования дубликатов в реестре npm. Мы указали лицензию MIT в поле license, что дает нам право на свободное использование и распространение кода приложения.

      Кроме того в файле указано следующее:

      • "main": точка входа приложения, app.js. Затем вы создадите этот файл.
      • "dependencies": зависимости проекта — в данном случае, Express 4.16.4 или более поздняя версия.

      Хотя этот файл не указан в хранилище, вы можете добавить его в соответствии со следующими указаниями по добавлению хранилища в файл package.json. Это хорошее дополнение, если вы задаете версии своего приложения.

      Сохраните и закройте файл, когда закончите вносить изменения.

      Чтобы установить зависимости проекта, выполните следующую команду:

      Пакеты, перечисленные вами в файле package.json, будут установлены в каталог вашего проекта.

      Теперь можно перейти к сборке файлов приложения.

      Шаг 2 — Создание файлов приложения

      Мы создадим сайт, который предоставляет пользователям данные об акулах. В нашем приложении будет основная точка входа, app.js, и каталог views, где будут находиться статичные активы проекта. Начальная страница index.html будет предоставлять пользователям предварительную информацию и ссылку на страницу с более подробной информацией об акулах, sharks.html. В каталоге views мы создадим начальную страницу и файл sharks.html.

      Вначале откройте файл app.js в главном каталоге проекта, чтобы определить маршруты проекта:

      Первая часть файла будет создавать приложение Express и объекты Router, а также определять базовый каталог и порт как постоянные величины:

      ~/node_project/app.js

      const express = require('express');
      const app = express();
      const router = express.Router();
      
      const path = __dirname + '/views/';
      const port = 8080;
      

      Функция require загружает модуль express, который мы используем для создания объектов app и router. Объект router будет выполнять функцию маршрутизации в приложении. Определяя маршруты методов HTTP, мы будем добавлять их в этот объект, чтобы определить, как наше приложение будет обрабатывать запросы.

      В этом разделе файла также содержатся две константы, path и port:

      • path: определяет базовый каталог, в данном случае подкаталог views в каталоге текущего проекта.
      • port: указывает приложению прослушивать и выполнить привязку к порту 8080.

      Затем настройте маршруты для приложения с помощью объекта router:

      ~/node_project/app.js

      ...
      
      router.use(function (req,res,next) {
        console.log("https://www.digitalocean.com/" + req.method);
        next();
      });
      
      router.get("https://www.digitalocean.com/", function(req,res){
        res.sendFile(path + 'index.html');
      });
      
      router.get("https://www.digitalocean.com/sharks", function(req,res){
        res.sendFile(path + 'sharks.html');
      });
      

      Функция router.use загружает промежуточную функцию, которая будет регистрировать запросы маршрутизатора и передавать их на маршруты приложения. Они определяются в последующих функциях, который указывают, что запрос GET базового URL проекта должен возвращать страницу index.html, а запрос GET для маршрута /sharks должен возвращать страницу sharks.html.

      Наконец, смонтируйте промежуточный уровень router и статичные ресурсы приложения и укажите приложению прослушивать порт 8080:

      ~/node_project/app.js

      ...
      
      app.use(express.static(path));
      app.use("https://www.digitalocean.com/", router);
      
      app.listen(port, function () {
        console.log('Example app listening on port 8080!')
      })
      

      Готовый файл app.js будет выглядеть примерно так:

      ~/node_project/app.js

      const express = require('express');
      const app = express();
      const router = express.Router();
      
      const path = __dirname + '/views/';
      const port = 8080;
      
      router.use(function (req,res,next) {
        console.log("https://www.digitalocean.com/" + req.method);
        next();
      });
      
      router.get("https://www.digitalocean.com/", function(req,res){
        res.sendFile(path + 'index.html');
      });
      
      router.get("https://www.digitalocean.com/sharks", function(req,res){
        res.sendFile(path + 'sharks.html');
      });
      
      app.use(express.static(path));
      app.use("https://www.digitalocean.com/", router);
      
      app.listen(port, function () {
        console.log('Example app listening on port 8080!')
      })
      

      Сохраните файл и закройте его после завершения.

      Далее добавим в приложение статичный контент. Вначале создадим каталог views:

      Откройте файл начальной страницы, index.html:

      Добавьте в файл следующий код, который импортирует Boostrap и создаст компонент jumbotron со ссылкой на страницу подробной информации о sharks.html:

      ~/node_project/views/index.html

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
          <title>About Sharks</title>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
          <link href="https://www.digitalocean.com/css/styles.css" rel="stylesheet">
          <link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
      </head>
      
      <body>
          <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md">
              <div class="container">
                  <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span>
                  </button> <a class="navbar-brand" href="https://www.digitalocean.com/#">Everything Sharks</a>
                  <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                      <ul class="nav navbar-nav mr-auto">
                          <li class="active nav-item"><a href="https://www.digitalocean.com/" class="nav-link">Home</a>
                          </li>
                          <li class="nav-item"><a href="https://www.digitalocean.com/sharks" class="nav-link">Sharks</a>
                          </li>
                      </ul>
                  </div>
              </div>
          </nav>
          <div class="jumbotron">
              <div class="container">
                  <h1>Want to Learn About Sharks?</h1>
                  <p>Are you ready to learn about sharks?</p>
                  <br>
                  <p><a class="btn btn-primary btn-lg" href="https://www.digitalocean.com/sharks" role="button">Get Shark Info</a>
                  </p>
              </div>
          </div>
          <div class="container">
              <div class="row">
                  <div class="col-lg-6">
                      <h3>Not all sharks are alike</h3>
                      <p>Though some are dangerous, sharks generally do not attack humans. Out of the 500 species known to researchers, only 30 have been known to attack humans.
                      </p>
                  </div>
                  <div class="col-lg-6">
                      <h3>Sharks are ancient</h3>
                      <p>There is evidence to suggest that sharks lived up to 400 million years ago.
                      </p>
                  </div>
              </div>
          </div>
      </body>
      
      </html>
      

      Навигационная панель верхнего уровня позволяет пользователям переключаться между страницами Home и Sharks. В субкомпоненте navbar-nav мы используем active класс Bootstrap, чтобы указать пользователю текущую страницу. Также мы указали маршруты наших статичных страниц, что соответствует маршрутам, определенным в файле app.js:

      ~/node_project/views/index.html

      ...
      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
         <ul class="nav navbar-nav mr-auto">
            <li class="active nav-item"><a href="https://www.digitalocean.com/" class="nav-link">Home</a>
            </li>
            <li class="nav-item"><a href="https://www.digitalocean.com/sharks" class="nav-link">Sharks</a>
            </li>
         </ul>
      </div>
      ...
      

      Кроме того, мы создали ссылку на страницу с информацией об акулах в нашей кнопке jumbotron:

      ~/node_project/views/index.html

      ...
      <div class="jumbotron">
         <div class="container">
            <h1>Want to Learn About Sharks?</h1>
            <p>Are you ready to learn about sharks?</p>
            <br>
            <p><a class="btn btn-primary btn-lg" href="https://www.digitalocean.com/sharks" role="button">Get Shark Info</a>
            </p>
         </div>
      </div>
      ...
      

      Также в заголовке имеется ссылка на пользовательскую таблицу стилей:

      ~/node_project/views/index.html

      ...
      <link href="https://www.digitalocean.com/css/styles.css" rel="stylesheet">
      ...
      

      Мы создадим эту таблицу стилей в конце данного шага.

      Сохраните файл и закройте его после завершения.

      Подготовив начальную страницу приложения, мы можем создать страницу с информацией об акулах, sharks.html, где заинтересованные пользователи смогут получить больше информации об акулах.

      Откройте файл:

      Добавьте следующий код, который импортирует Bootstrap и пользовательскую таблицу стилей и предлагает пользователям подробную информацию об определенных акулах:

      ~/node_project/views/sharks.html

      <!DOCTYPE html>
      <html lang="en">
      
      <head>
          <title>About Sharks</title>
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
          <link href="https://www.digitalocean.com/css/styles.css" rel="stylesheet">
          <link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
      </head>
      <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md">
          <div class="container">
              <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span>
              </button> <a class="navbar-brand" href="https://www.digitalocean.com/">Everything Sharks</a>
              <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                  <ul class="nav navbar-nav mr-auto">
                      <li class="nav-item"><a href="https://www.digitalocean.com/" class="nav-link">Home</a>
                      </li>
                      <li class="active nav-item"><a href="https://www.digitalocean.com/sharks" class="nav-link">Sharks</a>
                      </li>
                  </ul>
              </div>
          </div>
      </nav>
      <div class="jumbotron text-center">
          <h1>Shark Info</h1>
      </div>
      <div class="container">
          <div class="row">
              <div class="col-lg-6">
                  <p>
                      <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                      </div>
                      <img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
                  </p>
              </div>
              <div class="col-lg-6">
                  <p>
                      <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                      <img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
                  </p>
              </div>
          </div>
      </div>
      
      </html>
      

      В этом файле мы снова используем active класс для индикации текущей страницы.

      Сохраните файл и закройте его после завершения.

      Наконец, создайте пользовательскую таблицу стилей CSS, на которую вы разместили ссылки в файлах index.html и sharks.html. Для этого вначале создайте папку css в каталоге views:

      Откройте таблицу стилей:

      • nano views/css/styles.css

      Добавьте следующий код, который задаст желаемые цвет и шрифт для наших страниц:

      ~/node_project/views/css/styles.css

      .navbar {
          margin-bottom: 0;
      }
      
      body {
          background: #020A1B;
          color: #ffffff;
          font-family: 'Merriweather', sans-serif;
      }
      
      h1,
      h2 {
          font-weight: bold;
      }
      
      p {
          font-size: 16px;
          color: #ffffff;
      }
      
      .jumbotron {
          background: #0048CD;
          color: white;
          text-align: center;
      }
      
      .jumbotron p {
          color: white;
          font-size: 26px;
      }
      
      .btn-primary {
          color: #fff;
          text-color: #000000;
          border-color: white;
          margin-bottom: 5px;
      }
      
      img,
      video,
      audio {
          margin-top: 20px;
          max-width: 80%;
      }
      
      div.caption: {
          float: left;
          clear: both;
      }
      

      В дополнение к настройке шрифта и цвета этот файл также ограничивает размер изображений, указывая max-width 80%. Благодаря этому они не будут занимать больше места на странице, чем нам бы хотелось.

      Сохраните файл и закройте его после завершения.

      Теперь, когда файлы приложения готовы, а зависимости проекта установлены, вы готовы к запуску приложения.

      Если вы следовали указаниям руководства по первоначальной настройке сервера, указанного в предварительных условиях, у вас установлен активный брандмауэр, на котором разрешен только трафик SSH. Чтобы разрешить трафик на порт 8080, выполните команду:

      Чтобы запустить приложение, перейдите в каталог root вашего проекта:

      Запустите приложение с node app.js:

      Откройте в браузере адрес http://your_server_ip:8080. Вы увидите следующую начальную страницу:

      Начальная страница приложения

      Нажмите кнопку Get Shark Info (Получить информацию об акулах). Вы увидите следующую информационную страницу:

      Страница информации об акулах

      Ваше приложение запущено и работает. Когда вы будете готовы, покиньте сервер, нажав CTRL+C. Теперь мы можем перейти к созданию файла Dockerfile, который позволит нам воссоздать и масштабировать это приложение, когда это потребуется.

      Шаг 3 — Создание файла Dockerfile

      Ваш файл Dockerfile указывает, что будет включено в контейнер приложения при его выполнении. Использование Dockerfile позволяет определить среду контейнера и избежать расхождений с зависимостями и версиями модуля исполнения.

      В соответствии с этими указаниями по построению оптимизированных контейнеров, мы сделаем наше изображение максимально эффективным, минимизируем количество слоев образа и воссоздадим файлы нашего приложения и статичный контент.

      Создайте файл Dockerfile в каталоге root вашего проекта:

      Образы Docker создаются с использованием последовательности многослойных образов, накладывающихся друг поверх друга. Вначале мы добавим базовый образ нашего приложения, который станет начальной точкой сборки приложения.

      Мы будем использовать образ node:10-alpine, поскольку на момент написания это рекомендуемая версия LTS Node.js. Образ alpine является производным проекта Alpine Linux, и это помогает уменьшить размер образа. Дополнительную информацию о том, стоит ли использовать образ alpine в вашем проекте, можно получить в полном обсуждении в разделе *Image Variants *(Варианты образов) на странице образов Docker Hub Node.

      Добавьте следующую команду FROM, чтобы задать базовый образ приложения:

      ~/node_project/Dockerfile

      FROM node:10-alpine
      

      Этот образ включает Node.js и npm. Каждый Dockerfile должен начинаться с команды FROM.

      По умолчанию образ Docker Node включает пользователя node, не являющегося пользователем root, которого вы можете использовать, чтобы контейнер вашего приложения не запускался как root. Для безопасности рекомендуется не запускать контейнеры как пользователь root и ограничить возможности контейнера теми, которые необходимы для запуска его процессов. Мы используем домашний каталог пользователя node как рабочий каталог нашего приложения и зададим его как пользователя внутри контейнера. Дополнительную информацию об оптимальной практике работы с образом Docker Node можно найти в этом руководстве по передовым практикам.

      Для тонкой настройки разрешений кода приложения в контейнере создадим подкаталог node_modules в каталоге /home/node вместе с каталогом app. Создание этих каталогов обеспечит наличие желаемых разрешений, что будет важно при создании локальных модулей узла в контейнере с помощью команды npm install. В дополнение к созданию этих каталогов мы зададим пользователя node как их владельца:

      ~/node_project/Dockerfile

      ...
      RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
      

      Дополнительную информацию о полезности консолидации команд RUN можно найти в этой дискуссии об управлении слоями контейнеров.

      Далее установите рабочий каталог приложения /home/node/app:

      ~/node_project/Dockerfile

      ...
      WORKDIR /home/node/app
      

      Если WORKDIR не задан, Docker создаст рабочий каталог по умолчанию, и поэтому лучше явно задать его.

      Далее скопируйте файлы package.json и package-lock.json (для npm 5+):

      ~/node_project/Dockerfile

      ...
      COPY package*.json ./
      

      Добавление этой команды COPY перед запуском npm install или копированием кода приложения позволяет использовать механизм кэширования Docker. На каждом этапе сборки Docker проверяет наличие кэшированного слоя для этой конкретной команды. Если мы изменим файл package.json, этот слой будет построен заново, но если мы не будем его менять, данная команда позволит Docker использовать существующий слой образа и пропустить повторную установку модулей узла.

      Чтобы все файлы приложения принадлежали пользователю node, не являющемуся пользователем root, включая содержимое каталога node_modules, переключитесь на пользователя *node *перед запуском npm install:

      ~/node_project/Dockerfile

      ...
      USER node
      

      После копирования зависимостей проекта и переключения пользователя можно запустить npm install:

      ~/node_project/Dockerfile

      ...
      RUN npm install
      

      Затем скопируйте код приложения с надлежащими разрешениями в каталог приложения в контейнере:

      ~/node_project/Dockerfile

      ...
      COPY --chown=node:node . .
      

      В этом случае файлы приложения будут принадлежать пользователю node, не являющемуся пользователем root.

      Наконец, откройте порт 8080 в контейнере и запустите приложение:

      ~/node_project/Dockerfile

      ...
      EXPOSE 8080
      
      CMD [ "node", "app.js" ]
      

      Команда EXPOSE не публикует порт, но служит для документирования портов контейнера, которые будут публиковаться во время исполнения. CMD выполняет команду пуска приложения, в данном случае node app.js. Обратите винмание, что в каждом файле Dockerfile должна быть только одна команда CMD. Если вы включите несколько команд, действовать будет только последняя.

      С помощью Dockerfile можно сделать много разных вещей. Полный список команд можно найти в справочной документации по Dockerfile.

      Полный файл Dockerfile выглядит следующим образом:

      ~/node_project/Dockerfile

      
      FROM node:10-alpine
      
      RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
      
      WORKDIR /home/node/app
      
      COPY package*.json ./
      
      USER node
      
      RUN npm install
      
      COPY --chown=node:node . .
      
      EXPOSE 8080
      
      CMD [ "node", "app.js" ]
      

      Сохраните и закройте файл после завершения редактирования.

      Прежде чем строить образ приложения, добавим файл .dockerignore. Работая аналогично файлу .gitignore, файл .dockerignore указывает, какие файлы и каталоги в каталоге проекта не следует копировать в контейнер.

      Откройте файл .dockerignore:

      Внутри файла добавьте модули локального узла, журналы npm, файл Dockerfile и файл .dockerignore:

      ~/node_project/.dockerignore

      node_modules
      npm-debug.log
      Dockerfile
      .dockerignore
      

      Если вы работаете с Git, также следует добавить каталог .git и файл .gitignore.

      Сохраните файл и закройте его после завершения.

      Теперь вы готовы к созданию образа прложения с помощью команды docker build. Использование флага -t с командой docker build позволяет присвоить образу метку с запоминающимся названием. Поскольку мы планируем размещать образ в Docker Hub, добавим в метку имя пользователя Docker Hub. Мы пометим образ меткой nodejs-image-demo, но вы можете использовать любое другое название на свое усмотрение. Также замените your_dockerhub_username своим именем пользователя Docker Hub:

      • docker build -t your_dockerhub_username/nodejs-image-demo .

      Символ . указывает, что контекст команды build — текущий каталог.

      Создание образа займет одну или две минуты. После завершения проверьте образы:

      Результат будет выглядеть следующим образом:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 8 seconds ago 73MB node 10-alpine f09e7c96b6de 3 weeks ago 70.7MB

      Теперь вы можете создать контейнер с этим образом, используя команду docker run. Мы добавим к этой команде три флага:

      • -p: публикует порт контейнера и сопоставляет его с портом хоста. Мы используем порт 80 на нашем хосте, но вы можете использовать любой другой порт, если этот порт занят каким-то другим процессом. Дополнительную информацию по принципам привязки портов можно найти в соответствующей документации Docker.
      • -d: запускает контейнер в фоновом режиме.
      • --name: позволяет присвоить контейнеру запоминающееся имя.

      Запустите следующую команду для построения контейнера:

      • docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo

      После запуска контейнера вы можете проверить список запущенных контейнеров с помощью команды docker ps:

      Результат будет выглядеть следующим образом:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e50ad27074a7 your_dockerhub_username/nodejs-image-demo "node app.js" 8 seconds ago Up 7 seconds 0.0.0.0:80->8080/tcp nodejs-image-demo

      Во время работы контейнера вы можете открыть свое приложение, указав в браузере адрес http://your_server_ip. После этого откроется начальная страница вашего приложения:

      Начальная страница приложения

      Вы создали образ приложения, и теперь можете опубликовать его в Docker Hub для будущего использования.

      Шаг 4 — Использование хранилища для работы с образами

      При публикации образа приложения в таком реестре как Docker Hub вы делаете его доступным для последующего использования при построении и масштабировании контейнеров. Для примера мы покажем, как разместить образ приложения в хранилище и использовать его для воссоздания контейнера.

      Прежде всего необходимо войти в учетную запись Docker Hub, созданную в соответствии с предварительными требованиями:

      • docker login -u your_dockerhub_username

      Введите пароль учетной записи Docker Hub в соответствующем диалоговом окне. При входе в каталоге home вашего пользователя будет создан файл ~/.docker/config.json с вашими учетными данными Docker Hub.

      Теперь вы можете записать образ приложения в Docker Hub, используя ранее созданную метку your_dockerhub_username/nodejs-image-demo:

      • docker push your_dockerhub_username/nodejs-image-demo

      Давайте проверим использование реестра образов. Для этого уничтожим текущий контейнер приложения и образ и воссоздадим их на основе образа из хранилища.

      Вначале перечислите запущенные контейнеры:

      Результат будет выглядеть следующим образом:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e50ad27074a7 your_dockerhub_username/nodejs-image-demo "node app.js" 3 minutes ago Up 3 minutes 0.0.0.0:80->8080/tcp nodejs-image-demo

      Остановите запущенный контейнер приложения, используя идентификатор CONTAINER ID, показанный в результатах. Обязательно замените выделенный ниже идентификатор собственным идентификатором CONTAINER ID:

      Перечислите все образы, используя флаг -a:

      Вы увидите следующие результаты с именем образа your_dockerhub_username/nodejs-image-demo, а также образом узла и другими образами из вашей сборки:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 7 minutes ago 73MB <none> <none> 2e3267d9ac02 4 minutes ago 72.9MB <none> <none> 8352b41730b9 4 minutes ago 73MB <none> <none> 5d58b92823cb 4 minutes ago 73MB <none> <none> 3f1e35d7062a 4 minutes ago 73MB <none> <none> 02176311e4d0 4 minutes ago 73MB <none> <none> 8e84b33edcda 4 minutes ago 70.7MB <none> <none> 6a5ed70f86f2 4 minutes ago 70.7MB <none> <none> 776b2637d3c1 4 minutes ago 70.7MB node 10-alpine f09e7c96b6de 3 weeks ago 70.7MB

      Удалите остановленный контейнер и все образы, включая неиспользуемые или недействительные образы, с помощью следующей команды:

      Введите y в диалоговом окне, чтобы подтвердить удаление остановленного контейнера и образов. Помните, что при этом также будет удален кэш вашей сборки.

      Теперь вы удалили контейнер с образом приложения и сам образ. Дополнительную информацию об удалении контейнеров Docker, образов и томов можно найти в документе «Удаление образов, контейнеров и томов Docker».

      Удалив все образы и контейнеры, вы можете извлечь образ приложения из Docker Hub:

      • docker pull your_dockerhub_username/nodejs-image-demo

      Еще раз перечислите образы:

      Вы увидите образ вашего приложения:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE your_dockerhub_username/nodejs-image-demo latest 1c723fb2ef12 11 minutes ago 73MB

      Теперь вы можете воссоздать свой контейнер, используя команду из шага 3:

      • docker run --name nodejs-image-demo -p 80:8080 -d your_dockerhub_username/nodejs-image-demo

      Перечислите запущенные контейнеры:

      Output

      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f6bc2f50dff6 your_dockerhub_username/nodejs-image-demo "node app.js" 4 seconds ago Up 3 seconds 0.0.0.0:80->8080/tcp nodejs-image-demo

      Посетите http://your_server_ip еще раз, чтобы просмотреть запущенное приложение.

      Заключение

      В этом обучающем руководстве вы создали статическое веб-приложение с Express и Bootstrap, а также образ Docker для этого приложения. Вы использовали этот образ для создания контейнера и разместили его в Docker Hub. Затем вы смогли уничтожить образ и контейнер и воссоздать их с помощью хранилища Docker Hub.

      Если вы хотите узнать больше о работе с такими инструментами, как Docker Compose и Docker Machine для создания мультиконтейнерных систем, вы можете ознакомиться со следующими руководствами:

      Общие советы по работе с данными контейнера можно найти здесь:

      Если вы интересуетесь другими темами по Docker, ознакомьтесь с нашей полной библиотекой обучающих пособий по Docker.



      Source link