[Перевод] Создание CI/CD-цепочки и автоматизация работы с Docker

Я написала мои первые сайты в конце 90-х. Тогда приводить их в рабочее состояние было очень просто. Был Apache-сервер на каком-нибудь общем хостинге, на этот сервер можно было войти по FTP, написав в браузерной строке нечто вроде ftp://ftp.example.com. Потом надо было ввести имя и пароль и выгрузить файлы на сервер. Другие были времена, всё тогда было проще, чем сейчас.

cgbvchdac53hqrfbqadsqimp0oa.jpeg

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

Для моего персонального проекта у меня была особая конфигурация. И я знала, что мне нужна возможность разворачивать сайт в продакшне, выполняя всего одно действие: запись кода в ветку master на GitHub. Я, кроме того, знала, что мне, для обеспечения работы моего маленького веб-приложения, не хочется заниматься управлением огромным кластером Kubernetes, или пользоваться технологией Docker Swarm, или поддерживать парк серверов с подами, агентами и всякими другими сложностями. Для того чтобы достичь цели по максимальному упрощению работы, мне понадобилось познакомиться с CI/CD.

Если у вас имеется маленький проект (в нашем случае речь идёт о Node.js-проекте) и вам хотелось бы узнать о том, как автоматизировать развёртывание этого проекта, сделав при этом так, чтобы то, что хранится в репозитории, в точности соответствовало бы тому, что работает в продакшне, то, полагаю, вас может заинтересовать эта статья.

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


Ожидается, что читатель этой статьи имеет базовые знания в области работы с командной строкой и написания Bash-скриптов. Кроме того, ему понадобятся учётные записи Travis CI и Docker Hub.

Цели


Не скажу, что эта статья может безоговорочно называться «учебным руководством». Это — скорее документ, в котором я рассказываю о том, что узнала, и описываю устраивающий меня процесс тестирования и развёртывания кода в продакшне, выполняемый за один автоматизированный проход.

Вот каким в итоге получился мой рабочий процесс.

Для кода, отправленного в любую ветку репозитория, кроме master, производятся такие действия:

  • Запускается сборка проекта на Travis CI.
  • Выполняются все модульные, интеграционные и сквозные тесты.


Только для кода, который попадает в master, выполняется следующее:

  • Всё то, о чём сказано выше, плюс…
  • Сборка образа Docker на основании текущего кода, настроек и окружения.
  • Размещение образа на Docker Hub.
  • Подключение к продакшн-серверу.
  • Загрузка образа с Docker Hub на сервер.
  • Остановка текущего контейнера и запуск нового, основанного на новом образе.


Если вы совершенно ничего не знаете о Docker, об образах и контейнерах — не беспокойтесь. Я об этом всём вам расскажу.

Что такое CI/CD?


Аббревиатура CI/CD расшифровывается как «continuous integration/continuous deployment» — «непрерывная интеграция/непрерывное развёртывание».

▍Непрерывная интеграция


Непрерывная интеграция — это процесс, в ходе которого разработчики делают коммиты в главное хранилище исходного кода проекта (обычно в ветку master). При этом качество кода обеспечивается путём проведения автоматизированного тестирования.

▍Непрерывное развёртывание


Непрерывное развёртывание — это частое автоматизированное развёртывание кода в продакшне. Вторая часть аббревиатуры CI/CD иногда раскрывается как «continuous delivery» («непрерывная доставка»). Это, в целом, то же самое, что и «непрерывное развёртывание», но «непрерывная доставка» подразумевает необходимость ручного подтверждения изменений перед запуском процесса развёртывания проекта.

Начало работы


Приложение, на котором я это всё осваивала, называется TakeNote. Это — веб-проект, над которым я работаю, предназначенный для того, чтобы делать заметки. Сначала я попыталась сделать JAMStack-проект, или только фронтенд-приложение без сервера, для того чтобы воспользоваться стандартными возможностями по хостингу и развёртыванию проектов, которые предлагает Netlify. По мере того, как росла сложность приложения, мне понадобилось создать и его серверную часть, а это означало, что мне надо было бы сформировать собственную стратегию по автоматизированной интеграции и автоматизированному развёртыванию проекта.

В моём случае приложение представляет собой Express-сервер, работающий в среде Node.js, обслуживающий одностраничное React-приложение и поддерживающий защищённый серверный API. Эта архитектура следует стратегии, которую можно найти в данном руководстве по фуллстек-аутентификации.

Я посоветовалась с другом, который является экспертом по автоматизации, и спросила его о том, что мне надо сделать для того, чтобы всё это работало так, как мне нужно. Он подкинул мне идею о том, как должен выглядеть автоматизированный рабочий процесс, изложенный в разделе «Цели» этой статьи. То, что я поставила перед собой подобные цели, означало, что мне нужно разобраться в том, как пользоваться Docker.

Docker


Docker — это инструмент, который, благодаря технологии контейнеризации, позволяет легко распространять приложения, а также выполнять их развёртывание и запуск в одном и том же окружении даже в том случае, если сама платформа Docker работает в различных средах. Для начала мне нужно было получить в своё распоряжение инструменты командной строки (CLI) Docker. Инструкцию по установке Docker нельзя назвать очень чёткой и понятной, но из неё можно узнать о том, что для того, чтобы сделать первый шаг установки, надо скачать Docker Desktop (для Mac или Windows).

Docker Hub — это примерно то же самое, что GitHub для git-репозиториев, или реестр npm для JavaScript-пакетов. Это — онлайн-репозиторий для образов Docker. Именно к нему подключается Docker Desktop.

Итак, для того чтобы приступить к работе с Docker, нужно сделать две вещи:


После этого можете проверить работоспособность Docker CLI, выполнив следующую команду для проверки версии Docker:

docker -v


Далее, войдите в Docker Hub, введя, когда вас об этом спросят, свое имя пользователя и пароль:

docker login


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

▍Образы


Образ — это нечто вроде плана, содержащего инструкции по сборке контейнера. Это неизменяемый снимок файловой системы и настроек приложения. Разработчики могут с лёгкостью обмениваться образами.

# Вывод сведений обо всех образах
docker images


Эта команда выведет таблицу со следующим заголовком:

REPOSITORY     TAG     IMAGE ID     CREATED     SIZE
---


Далее мы будем рассматривать некоторые примеры команд в таком же формате — сначала идёт команда с комментарием, а потом — пример того, что она может вывести.

▍Контейнеры


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

# Перечисление всех контейнеров
docker ps -a
CONTAINER ID     IMAGE     COMMAND     CREATED     STATUS     PORTS     NAMES
---


▍Теги


Тег — это указание на конкретную версию образа.

▍Краткая справка по командам Docker


Вот обзор некоторых часто используемых команд Docker.

▍Файл Dockerfile


Я знаю, как локально запустить приложение для продакшна. У меня есть Webpack-конфигурация, предназначенная для сборки готового React-приложения. Далее, у меня имеется команда, запускающая сервер, основанный на Node.js, на порте 5000. Выглядит это так:

npm i         # установка зависимостей
npm run build # сборка React-приложения
npm run start # запуск Node-сервера


Надо отметить, что у меня нет приложения-примера для этого материала. Но тут, для экспериментов, подойдёт любое простое Node-приложение.

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

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

  • FROM — Эта команда начинает файл. В ней указывается базовый образ, на основе которого строится контейнер.
  • COPY — Копирование файлов из локального источника в контейнер.
  • WORKDIR — Установка рабочей директории для следующих команд.
  • RUN — Запуск команд.
  • EXPOSE — Настройка порта.
  • ENTRYPOINT — Указание выполняемой команды.


Dockerfile может выглядеть примерно так:

# Загрузить базовый образ
FROM node:12-alpine

# Скопировать файлы из текущей директории в директорию app/
COPY . app/

# Использовать app/ в роли рабочей директории
WORKDIR app/

# Установить зависимости (команда npm ci похожа npm i, но используется для автоматизированных сборок)
RUN npm ci --only-production

# Собрать клиентское React-приложение для продакшна
RUN npm run build

# Прослушивать указанный порт
EXPOSE 5000

# Запустить Node-сервер
ENTRYPOINT npm run start


В зависимости от выбранного базового образа вам может понадобиться установить дополнительные зависимости. Дело в том, что некоторые базовые образы (вроде Node Alpine Linux) созданы с целью сделать их как можно более компактными. В результате в них могут отсутствовать некоторые программы, на которые вы рассчитываете.

▍Сборка, тегирование и запуск контейнера


Локальные сборка и запуск контейнера — это, после того, как у нас есть Dockerfile, задачи довольно простые. Прежде чем отправлять образ на Docker Hub, его нужно протестировать локально.

▍Сборка


Сначала надо собрать образ, указав имя, и, что необзательно, тег (если тег задан не будет, система автоматически назначит образу тег latest).

# Сборка образа
docker build -t : .


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

Sending build context to Docker daemon   2.88MB
Step 1/9 : FROM node:12-alpine
 ---> ...выполнение этапов сборки...
Successfully built 123456789123
Successfully tagged :


Сборка может занять пару минут — тут всё зависит от того, сколько у вас имеется зависимостей. После завершения сборки можно выполнить команду docker images и взглянуть на описание своего нового образа.

REPOSITORY          TAG               IMAGE ID            CREATED              SIZE
             latest            123456789123        About a minute ago   x.xxGB


▍Запуск


Образ создан. А это значит, что на его основе можно запустить контейнер. Так как я хочу, чтобы у меня была бы возможность обращаться к приложению, работающему в контейнере, по адресу localhost:5000, я, в левой части пары 5000:5000 в следующей команде установила 5000. В правой части находится порт контейнера.

# Запуск с использованием локального порта 5000 и порта контейнера 5000
docker run -p 5000:5000 :


Теперь, когда контейнер создан и запущен, можно воспользоваться командой docker ps для того чтобы взглянуть на сведения об этом контейнере (или можно воспользоваться командой docker ps -a, которая выводит сведения обо всех контейнерах, а не только о работающих).

CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                      PORTS                    NAMES
987654321234                     "/bin/sh -c 'npm run…"   6 seconds ago        Up 6 seconds                0.0.0.0:5000->5000/tcp   stoic_darwin


Если перейти теперь по адресу localhost:5000 — можно увидеть страницу работающего приложения, которая выглядит точно так же, как страница приложения, работающего в продакшн-окружении.

▍Назначение тега и публикация


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

Теперь можно собрать образ с назначением ему нового имени и выполнить команду docker push для отправки его в репозиторий Docker Hub.

docker build -t /: .
docker tag /: /:latest
docker push /:

# На практике это может выглядеть, например, так:
docker build -t user/app:v1.0.0 .
docker tag user/app:v1.0.0 user/app:latest
docker push user/app:v1.0.0


Если всё пройдёт как надо, образ будет доступен на Docker Hub и его легко можно будет загрузить на сервер или передать другим разработчикам.

Следующие шаги


К настоящему моменту мы убедились в том, что приложение, в виде контейнера Docker, работает локально. Мы загрузили контейнер на Docker Hub. Всё это значит, что мы уже очень неплохо продвинулись к цели. Теперь надо решить ещё два вопроса:

  • Настройка CI-инструмента для тестирования и развёртывания кода.
  • Настройка продакшн-сервера так, чтобы он мог бы загружать и запускать наш код.


В нашем случае в качестве CI/CD-решения используется Travis CI. В качестве сервера — DitigalOcean.

Надо отметить, что здесь можно воспользоваться и другой комбинацией сервисов. Например, вместо Travis CI можно воспользоваться CircleCI или Github Actions. А вместо DigitalOcean — AWS или Linode.

Мы решили работать с Travis CI, а в этом сервисе у меня уже кое-что настроено. Поэтому сейчас я кратко расскажу о том, как подготовить его к работе.

Travis CI


Travis CI — это инструмент для тестирования и развёртывания кода. Мне не хотелось бы входить в тонкости настройки Travis CI, так как каждый проект уникален, и это не принесёт особой пользы. Но я расскажу об основах, которые позволят вам начать работу в том случае, если вы решите пользоваться Travis CI. Что бы вы ни выбрали — Travis CI, CircleCI, Jenkins, или что-то другое, везде будут применяться похожие методы настройки.

Для того чтобы приступить к работе с Travis CI, перейдите на сайт проекта и создайте учётную запись. Затем интегрируйте Travis CI с вашим GitHub-аккаунтом. Вам, в ходе настройки системы, понадобится указать репозиторий, работу с которым вы хотите автоматизировать, и включить доступ к нему. (Я пользуюсь GitHub, но уверена, что Travis CI может интегрироваться и с BitBucket, и с GitLab, и с другими подобными сервисами).

Каждый раз, когда Travis CI принимается за работу, запускается сервер, выполняющий указанные в конфигурационном файле команды, включая развёртывание соответствующих веток репозитория.

▍Жизненный цикл задания


Конфигурационный файл Travis CI, называемый .travis.yml и хранящийся в корневой директории проекта, поддерживает концепцию событий жизненного цикла задания. Вот эти события, приведённые в том порядке, в котором они происходят:

  • apt addons
  • cache components
  • before_install
  • install
  • before_script
  • script
  • before_cache
  • after_success или after_failure
  • before_deploy
  • deploy
  • after_deploy
  • after_script


▍Тестирование


В конфигурационном файле я собираюсь настроить локальный сервер Travis CI. В качестве языка я выбрала Node 12 версии и указала системе на то, что нужно установить зависимости, необходимые для использования Docker.

Всё, что перечислено в .travis.yml, будет выполняться при выполнении всех pull-запросов во все ветки репозитория, если только не указано иное. Это полезная особенность, так как она означает, что мы можем тестировать весь код, поступающий в репозиторий. Это позволяет знать о том, готов ли код к записи в ветку master, и не нарушит ли он процесс сборки проекта. В этой глобальной конфигурации я устанавливаю всё локально, запускаю сервер разработчика Webpack в фоне (это — особенность моего рабочего процесса) и выполняю тесты.

Если вы хотите, чтобы в вашем репозитории выводились бы значки со сведениями о покрытии кода тестами, тут вы можете найти краткую инструкцию об использовании Jest, Travis CI и Coveralls для сбора и вывода этих сведений.

Итак, вот содержимое файла .travis.yml:

# Установить язык
language: node_js

# Установить версию Node.js
node_js:
  - '12'

services:
  # Использовать командную строку Docker
  - docker

install:
  # Установить зависимости для тестов
  - npm ci

before_script:
  # Запустить сервер и клиент для тестов
  - npm run dev &

script:
  # Запустить тесты
  - npm run test


Здесь заканчиваются те действия, которые выполняются для всех ветвей репозитория и для pull-запросов.

▍Развёртывание


Исходя из предположения о том, что все автоматизированные тесты завершились успешно, мы, что делать необязательно, можем развернуть код на продакшн-сервере. Так как мы хотим делать это лишь для кода из ветки master, мы даём системе соответствующие указания в настройках развёртывания. Прежде чем вы попробуете воспользоваться в своём проекте кодом, который мы рассмотрим дальше, я хотела бы предупредить вас о том, что у вас должен быть реальный скрипт, вызываемый для развёртывания.

deploy:
  # Собрать Docker-контейнер и отправить его на Docker Hub
  provider: script
  script: bash deploy.sh
  on:
    branch: master


Скрипт развёртывания решает две задачи:

  • Сборка, тегирование и отправка образа на Docker Hub средствами CI-инструмента (в нашем случае это Travis CI).
  • Загрузка образа на сервере, остановка старого контейнера и запуск нового (в нашем случае сервер работает на платформе DigitalOcean).


Сначала нужно настроить автоматический процесс сборки, тегирования и отправки образа на Docker Hub. Всё это очень похоже на то, что мы уже делали вручную, за исключением того, что тут нам нужна стратегия назначения образам уникальных тегов и автоматизация входа в систему. У меня были сложности с некоторыми деталями скрипта развёртывания, с такими, как стратегия тегирования, вход в систему, кодировка SSH-ключей, установление SSH-соединения. Но, к счастью, мой бойфренд очень хорошо управляется с bash, как и со многими другими вещами. Он помог мне написать этот скрипт.

Итак, первая часть скрипта — это отправка образа на Docker Hub. Сделать это довольно просто. Использованная мной схема составления тегов подразумевает комбинирование git-хэша и git-тега, если он существует. Это позволяет обеспечить создание уникального тега и упрощает идентификацию сборки, на которой он основан. DOCKER_USERNAME и DOCKER_PASSWORD — это пользовательские переменные окружения, которые можно задать с помощью интерфейса Travis CI. Travis CI автоматически обработает секретные данные так, чтобы они не попали в чужие руки.

Вот первая часть скрипт deploy.sh.

#!/bin/sh
set -e # Остановить скрипт при наличии ошибок

IMAGE="/"                             # Образ Docker
GIT_VERSION=$(git describe --always --abbrev --tags --long) # Git-хэш и теги

# Сборка и тегирование образа
docker build -t ${IMAGE}:${GIT_VERSION} .
docker tag ${IMAGE}:${GIT_VERSION} ${IMAGE}:latest

# Вход в Docker Hub и выгрузка образа
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker push ${IMAGE}:${GIT_VERSION}


То, какой будет вторая часть скрипта, полностью зависит от того, какой хост вы используете, и от того, как организовано подключение к нему. В моём случае, так как пользуюсь я Digital Ocean, для подключения к серверу используются команды doctl. При работе с Aws будет использоваться утилита aws, и так далее.

Настроить работу сервера было не особенно сложно. Так, я настроила дроплет, основанный на базовом образе. Надо отметить, что выбранная мной система требует выполнения однократной ручной установки Docker и однократного ручного запуска Docker. Я, для установки Docker, использовала Ubuntu 18.04, поэтому вы, если тоже используете Ubuntu, чтобы сделать то же самое, можете просто следовать этому простому руководству.

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

  • Нужно найти контейнер, который сейчас выполняется, и остановить его.
  • Затем нужно, в фоне, запустить новый контейнер.
  • Вам нужно будет установить локальный порт сервера в значение 80 — это позволит входить на сайт по адресу вида example.com, без указания порта, а не пользоваться адресом наподобие example.com:5000.
  • И, наконец, нужно удалить все старые контейнеры и образы.


Вот продолжение скрипта.

# Найти ID работающего контейнера
CONTAINER_ID=$(docker ps | grep takenote | cut -d" " -f1)

# Остановить старый контейнер, запустить новый, очистить систему
docker stop ${CONTAINER_ID}
docker run --restart unless-stopped -d -p 80:5000 ${IMAGE}:${GIT_VERSION}
docker system prune -a -f


Некоторые вещи, на которые стоит обратить внимание


Возможно, когда вы подключитесь к серверу по SSH из Travis CI, вы увидите предупреждение, которое не позволит продолжить установку, так как система будет ждать реакции пользователя.

The authenticity of host ' ()' can't be established.
RSA key fingerprint is .
Are you sure you want to continue connecting (yes/no)?


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

echo  | base64 # выводит <публичный ключ, закодированный в base64>


На практике эта команда может выглядеть так:

echo "123.45.67.89 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== you@example.com" | base64


А вот как выглядит то, что она выдаёт — строка в кодировке base64:

MTIzLjQ1LjY3Ljg5IHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQUJJd0FBQVFFQWtsT1Vwa0RIcmZIWTE3U2JybVRJcE5MVEdLOVRqb20vQldEU1UKR1BsK25hZnpsSERUWVc3aGRJNHlaNWV3MThKSDRKVzlqYmhVRnJ2aVF6TTd4bEVMRVZmNGg5bEZYNVFWa2JQcHBTd2cwY2RhMwpQYnY3a09kSi9NVHlCbFdYRkNSK0hBbzNGWFJpdEJxeGlYMW5LaFhwSEFac01jaUxxOFY2UmpzTkFRd2RzZE1GdlNsVksvN1hBCnQzRmFvSm9Bc25jTTFROXg1KzNWMFd3NjgvZUlGbWIxenVVRmxqUUpLcHJyWDg4WHlwTkR2allOYnk2dncvUGIwcndlcnQvRW4KbVorQVc0T1pQblRQSTg5WlBtVk1MdWF5ckQyY0U4NlovaWw4YitndzNyMysxbkthdG1Ja2puMnNvMWQwMVFyYVRsTXFWU3NieApOclJGaTl3cmYrTTdRPT0geW91QGV4YW1wbGUuY29tCg==


Вот команда, о которой говорилось выше

install:
  - echo < публичный ключ, закодированный в base64> | base64 -d >> $HOME/.ssh/known_hosts


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

Ещё одна вещь, на которую стоит обратить внимание, это то, что вам может понадобиться запустить весь скрипт развёртывания, представленный в виде одной строки, например — с помощью doctl. Это может потребовать некоторых дополнительных усилий.

doctl compute ssh  --ssh-command "все команды будут здесь && здесь"


TLS/SSL и балансировка нагрузки


После того, как я сделала всё то, о чём шла речь выше, последней вставшей передо мной проблемой стало то, что у сервера не было SSL. Так как я пользуюсь Node.js-сервером, для того, чтобы заставить работать обратный прокси Nginx и Let«s Encrypt, нужно изрядно повозиться.

Мне совсем не хотелось выполнять все эти SSL-настройки вручную, поэтому я просто создала балансировщик нагрузки и записала сведения о нём в DNS. В случае с DigitalOcean, например, создание автообновляемого самоподписываемого сертификата на балансировщике нагрузки — простая, бесплатная и быстрая процедура. У такого подхода есть и дополнительное преимущество, которое заключается в том, что это, если нужно, позволяет очень просто настроить SSL на множестве серверов, работающих за балансировщиком нагрузки. Это позволяет самим серверам совершенно не «задумываться» о SSL, но при этом использовать, как обычно, порт 80. Так что настройка SSL на балансировщике нагрузки — это гораздо проще и удобнее, чем альтернативные методы настройки SSL.

Теперь можно закрыть на сервере все порты, принимающие входящие соединения — кроме порта 80, используемого для связи с балансировщиком нагрузки, и порта 22 для SSH. В результате попытка прямого обращения к серверу по любым портам, за исключение этих двух, потерпит неудачу.

Итоги


После того, как я сделала всё то, о чём рассказала в этом материале, меня уже не пугала ни платформа Docker, ни концепции автоматизированных CI/CD-цепочек. Я смогла настроить цепочку непрерывной интеграции, в ходе выполнения которой производится тестирование кода до попадания его в продакшн и автоматическое развёртывание кода на сервере. Всё это для меня пока ещё относительно ново, и я уверена, что есть способы улучшить мой автоматизированный рабочий процесс и сделать его эффективнее. Поэтому если у вас есть идеи на этот счёт — дайте мне знать. Надеюсь, эта статья помогла вам в ваших делах. Мне хочется верить, что прочтя её, вы узнали столько же, сколько узнала я, пока разбиралась со всем тем, о чём в ней рассказала.

P.S. В нашем маркетплейсе имеется образ Docker, который устанавливается в один клик. Вы можете проверить работу контейнеров на VPS. Всем новым клиентам бесплатно предоставляются 3 дня для тестирования.

Уважаемые читатели! Пользуетесь ли вы технологиями CI/CD в своих проектах?

1ba550d25e8846ce8805de564da6aa63.png

© Habrahabr.ru