Criação de uma cadeia CI/CD e automação do trabalho com Docker

Eu criei meus primeiros sites no final dos anos 90. Naquela época, colocá-los em funcionamento era muito simples. Havia um servidor Apache em algum hospedagem compartilhada, a qual podia ser acessada via FTP, digitando na barra do navegador algo como ftp://ftp.example.com. Depois era necessário inserir o nome de usuário e a senha e fazer o upload dos arquivos para o servidor. Eram outros tempos, tudo era mais fácil do que agora.

Criação de uma cadeia CI/CD e automação do trabalho com Docker

Nas duas décadas que se passaram desde então, muita coisa mudou. Os sites se tornaram mais complexos, e antes de serem lançados em produção, precisam ser compilados. Um único servidor se transformou em múltiplos servidores trabalhando atrás de balanceadores de carga, e o uso de sistemas de controle de versões tornou-se algo comum.

Para o meu projeto pessoal, eu tinha uma configuração especial. E eu sabia que precisava da capacidade de implantar o site em produção fazendo apenas uma ação: gravando o código em uma branch master no GitHub. Além disso, eu sabia que para garantir o funcionamento do meu pequeno aplicativo web, não queria lidar com a gestão de um enorme cluster Kubernetes, ou usar a tecnologia Docker Swarm, ou manter um parque de servidores com pods, agentes e todas essas outras complexidades. Para atingir o objetivo de maximizar a simplicidade do trabalho, precisei me familiarizar com CI/CD.

Se você tem um pequeno projeto (no nosso caso, um projeto Node.js) e gostaria de saber como automatizar a implantação desse projeto, garantindo que o que está armazenado no repositório corresponda exatamente ao que está funcionando em produção, então, creio que este artigo pode ser do seu interesse.

Requisitos preliminares

Espera-se que o leitor deste artigo tenha conhecimentos básicos sobre como trabalhar com a linha de comando e escrever scripts Bash. Além disso, ele precisará de contas Travis CI e Docker Hub.

Objetivos

Não diria que este artigo pode ser chamado incondicionalmente de "manual de instruções". É mais um documento onde compartilho o que aprendi e descrevo o processo de teste e implantação de código em produção que me agrada, realizado em uma única passagem automatizada.

Aqui está como ficou o meu fluxo de trabalho.

Para o código enviado a qualquer branch do repositório, exceto master, são realizadas as seguintes ações:

  • A construção do projeto no Travis CI está sendo iniciada.
  • Todos os testes unitários, de integração e de ponta a ponta estão sendo executados.

Somente para o código que entra em master, o seguinte é executado:

  • Tudo o que foi mencionado acima, mais...
  • Construção da imagem Docker com base no código atual, configurações e ambiente.
  • Hospedagem da imagem no Docker Hub.
  • Conexão ao servidor de produção.
  • Carregamento da imagem do Docker Hub para o servidor.
  • Interrompendo o contêiner atual e iniciando um novo, baseado na nova imagem.

Se você não sabe nada sobre Docker, imagens ou contêineres — não se preocupe. Eu vou te contar tudo sobre isso.

O que é CI/CD?

A sigla CI/CD significa "continuous integration/continuous deployment" — "integração contínua/implantação contínua".

▍Integração Contínua

Integração contínua é o processo pelo qual os desenvolvedores realizam commits no repositório principal do código-fonte do projeto (geralmente no branch master). A qualidade do código é garantida por meio de testes automatizados.

▍Implantação Contínua

Implantação contínua é a implantação automatizada e frequente de código em produção. A segunda parte da sigla CI/CD às vezes é desdobrada como "continuous delivery" ("entrega contínua"). Isso, em geral, é o mesmo que "implantação contínua", mas "entrega contínua" implica a necessidade de aprovação manual das mudanças antes do início do processo de implantação do projeto.

Início

O aplicativo no qual estou aprendendo é chamado de TakeNote. Este é um projeto web no qual estou trabalhando, destinado a fazer anotações. No início, tentei criar um projeto JAMStack, ou apenas um aplicativo frontend sem servidor, para aproveitar as capacidades padrão de hospedagem e implantação de projetos que o Netlifyoferece. À medida que a complexidade do aplicativo aumentava, precisei criar também sua parte do servidor, e isso significava que eu precisaria desenvolver minha própria estratégia de integração e implantação automatizadas do projeto.

No meu caso, o aplicativo é um servidor Express que roda em um ambiente Node.js, servindo um aplicativo React de página única e suportando uma API segura. Essa arquitetura segue uma estratégia que pode ser encontrada em este guia sobre autenticação full-stack.

Conversei com um amigo, que é um especialista em automação, e perguntei a ele o que eu precisava fazer para que tudo funcionasse como eu queria. Ele me deu a ideia de como deveria ser o fluxo de trabalho automatizado, descrito na seção "Objetivos" deste artigo. O fato de eu ter estabelecido objetivos assim significou que eu precisava entender como usar o Docker.

Docker

Docker é uma ferramenta que, graças à tecnologia de containerização, facilita a distribuição de aplicativos, além de permitir sua implantação e execução no mesmo ambiente, mesmo que a própria plataforma Docker opere em diferentes ambientes. Para começar, eu precisava das ferramentas de linha de comando (CLI) do Docker. O guia para instalação do Docker não pode ser considerado muito claro ou compreensível, mas dele é possível aprender que, para dar o primeiro passo na instalação, é necessário baixar o Docker Desktop (para Mac ou Windows).

O Docker Hub é mais ou menos o que GitHub para repositórios git, ou um registro npm para pacotes JavaScript. É um repositório online para imagens Docker. É a ele que o Docker Desktop se conecta.

Assim, para começar a trabalhar com o Docker, você precisa fazer duas coisas:

Depois disso, você pode verificar se o Docker CLI está funcionando, executando o seguinte comando para verificar a versão do Docker:

docker -v

Em seguida, faça login no Docker Hub, digitando, quando solicitado, seu nome de usuário e senha:

docker login

Para usar o Docker, você deve entender os conceitos de imagens e contêineres.

▍Imagens

Uma imagem é como um plano que contém instruções para montar um contêiner. É uma captura de tela imutável do sistema de arquivos e configurações do aplicativo. Os desenvolvedores podem trocar imagens com facilidade.

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

Esse comando produzirá uma tabela com o seguinte cabeçalho:

REPOSITORY     TAG     IMAGE ID     CREATED     SIZE
---

A seguir, vamos analisar alguns exemplos de comandos no mesmo formato — primeiro vem o comando com um comentário, e depois — um exemplo do que ele pode gerar.

▍Contêineres

Um contêiner é um pacote executável que contém tudo o que é necessário para executar um aplicativo. Com essa abordagem, o aplicativo sempre funcionará de forma idêntica, independentemente da infraestrutura: em um ambiente isolado e na mesma configuração. O que está em discussão é que diferentes instâncias da mesma imagem são executadas em diferentes ambientes.

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

▍Tags

Uma tag é uma indicação de uma versão específica da imagem.

▍Resumo das Comandos Docker

Aqui está uma visão geral de alguns comandos Docker frequentemente usados.

Time

Contexto

Ação

docker build

Modelo

Construindo uma imagem a partir de um Dockerfile

docker tag

Modelo

Tagueando uma imagem

docker images

Modelo

Listando as imagens

docker run

O contêiner

Executando um contêiner baseado na imagem

docker push

Modelo

Enviando a imagem para o registro

docker pull

Modelo

Baixando a imagem do registro

docker ps

O contêiner

Listando os contêineres

docker system prune

Imagem/Contêiner

Removendo contêineres e imagens não utilizados

▍Arquivo Dockerfile

Eu sei como executar um aplicativo localmente para produção. Tenho uma configuração Webpack projetada para construir um aplicativo React pronto. A seguir, tenho um comando que inicia um servidor baseado em Node.js, na porta 5000. Isso se parece com:

npm i         # instalando dependências
npm run build # construindo o aplicativo React
npm run start # iniciando o servidor Node

É importante notar que não tenho um aplicativo de exemplo para este material. Mas para experimentos, qualquer aplicativo Node simples servirá.

Para usar o contêiner, você precisará fornecer instruções ao Docker. Isso é feito através de um arquivo chamado Dockerfile, que está localizado na raiz do projeto. Esse arquivo, a princípio, pode parecer um pouco confuso.

Mas o que ele contém é simplesmente uma descrição, usando comandos especiais, de algo semelhante à configuração de um ambiente de trabalho. Aqui estão alguns desses comandos:

  • FROM — Este comando inicia o arquivo. Ele especifica a imagem base na qual o contêiner será construído.
  • COPY — Copiando arquivos de uma fonte local para o contêiner.
  • WORKDIR — Definindo o diretório de trabalho para os comandos seguintes.
  • RUN — Executando comandos.
  • EXPOSE — Configurando a porta.
  • ENTRYPOINT — Especificando o comando a ser executado.

Dockerfile pode parecer algo assim:

# Загрузить базовый образ
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

Dependendo da imagem base escolhida, você pode precisar instalar dependências adicionais. O fato é que algumas imagens base (como Node Alpine Linux) são criadas com o objetivo de serem o mais compactas possível. Como resultado, podem faltar alguns programas que você espera.

▍Construção, marcação e execução do contêiner

A construção e a execução locais do contêiner — são, depois que temos Dockerfile, tarefas bastante simples. Antes de enviar a imagem para o Docker Hub, ela precisa ser testada localmente.

▍Construção

Primeiro, você precisa construir a imagem, especificando um nome e, opcionalmente, uma tag (se a tag não for definida, o sistema atribuirá automaticamente a tag latest).

# Сборка образа
docker build -t <image>:<tag> .

Após a execução desta comando, você poderá observar como o Docker realiza a construção da imagem.

Enviando contexto de construção para o daemon Docker   2.88MB
Passo 1/9 : FROM node:12-alpine
 ---> ...executando etapas de construção...
Construído com sucesso 123456789123
Tagueado com sucesso <image>:<tag>

A construção pode demorar alguns minutos — aqui tudo depende de quantas dependências você possui. Após a conclusão da construção, você pode executar o comando docker images e ver a descrição da sua nova imagem.

REPOSITÓRIO        TAG               ID DA IMAGEM        CRIADO              TAMANHO
<image>           latest            123456789123        Há cerca de um minuto   x.xxGB

▍Execução

A imagem foi criada. Isso significa que agora você pode executar um contêiner com base nela. Como quero poder acessar o aplicativo funcionando no contêiner pelo endereço localhost:5000, eu, na parte esquerda do par 5000:5000 na seguinte comando estabeleci 5000. Na parte direita está a porta do contêiner.

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

Agora que o contêiner foi criado e iniciado, você pode usar o comando docker ps para ver as informações sobre este contêiner (ou pode usar o comando docker ps -a, que mostra informações sobre todos os contêineres, não apenas os que estão em funcionamento).

ID DO CONTÊINER        IMAGEM               COMANDO                  CRIADO              STATUS                      PORTAS                    NOMES
987654321234        <image>             "\/bin\/sh -c 'npm run…"   6 segundos atrás        Em funcionamento há 6 segundos                0.0.0.0:5000->5000\/tcp   stoic_darwin

Se você agora acessar localhost:5000 — poderá ver a página do aplicativo em funcionamento, que é idêntica à página do aplicativo em um ambiente de produção.

▍Atribuição de tag e publicação

Para usar uma das imagens criadas no servidor de produção, precisamos ter a capacidade de carregar essa imagem do Docker Hub. Isso significa que primeiro precisamos criar um repositório no Docker Hub para o projeto. Depois disso, teremos um local para onde podemos enviar a imagem. A imagem deve ser renomeada para que seu nome comece com nosso nome de usuário no Docker Hub. Em seguida, deve vir o nome do repositório. No final do nome, pode haver qualquer tag. Abaixo está um exemplo de nomeação de imagens seguindo esse esquema.

Agora podemos construir a imagem com um novo nome e executar o comando docker push para enviá-la ao repositório do Docker Hub.

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

# Na prática isso pode ser feito assim:
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

Se tudo correr como esperado, a imagem estará disponível no Docker Hub e poderá ser facilmente carregada no servidor ou compartilhada com outros desenvolvedores.

Próximos passos

Até este momento, confirmamos que o aplicativo, na forma de um contêiner Docker, está funcionando localmente. Carregamos o contêiner no Docker Hub. Tudo isso significa que já avançamos muito em direção ao nosso objetivo. Agora precisamos resolver mais duas questões:

  • Configuração da ferramenta CI para testes e implementação do código.
  • Configuração do servidor de produção para que ele possa carregar e executar nosso código.

No nosso caso, estamos utilizando como solução CI\/CD Travis CI. Como servidor — DigitalOcean.

É importante notar que é possível usar uma combinação diferente de serviços. Por exemplo, em vez do Travis CI, podemos usar CircleCI ou Github Actions. E em vez do DigitalOcean — AWS ou Linode.

Decidimos trabalhar com o Travis CI, e neste serviço já tenho algumas configurações feitas. Portanto, agora vou explicar brevemente como prepará-lo para o trabalho.

Travis CI

Travis CI é uma ferramenta para testar e implantar código. Não gostaria de entrar nos detalhes da configuração do Travis CI, pois cada projeto é único e isso não traria muita vantagem. Mas vou falar sobre os fundamentos que permitirão que você comece a trabalhar caso decida usar o Travis CI. Seja o que for que você escolha — Travis CI, CircleCI, Jenkins, ou algo diferente, métodos semelhantes de configuração serão aplicados.

Para começar a trabalhar com o Travis CI, acesse o site do projeto e crie uma conta. Em seguida, integre o Travis CI à sua conta do GitHub. Durante a configuração do sistema, você precisará indicar o repositório que deseja automatizar e permitir acesso a ele. (Estou usando o GitHub, mas tenho certeza de que o Travis CI pode se integrar ao BitBucket, GitLab, e outros serviços semelhantes).

Toda vez que o Travis CI começa a trabalhar, um servidor é ativado para executar os comandos especificados no arquivo de configuração, incluindo a implantação dos ramos correspondentes do repositório.

▍Ciclo de vida da tarefa

O arquivo de configuração do Travis CI, chamado .travis.yml e armazenado no diretório raiz do projeto, suporta a concepção de eventos do ciclo de vida da tarefa. Aqui estão esses eventos, apresentados na ordem em que ocorrem:

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

▍Testes

No arquivo de configuração, irei configurar um servidor local do Travis CI. Escolhi a versão 12 do Node como linguagem e indiquei ao sistema que deve instalar as dependências necessárias para usar o Docker.

Tudo o que está listado em .travis.yml, será executado para todos os pull requests em todos os ramos do repositório, a menos que indicado o contrário. Essa é uma característica útil, pois significa que podemos testar todo o código que entra no repositório. Isso permite saber se o código está pronto para ser gravado no ramo master, e se ele não quebrará o processo de construção do projeto. Nesta configuração global, estou instalando tudo localmente, executando o servidor de desenvolvimento do Webpack em segundo plano (essa é uma característica do meu fluxo de trabalho) e realizando os testes.

Se você deseja que o seu repositório exiba ícones com informações sobre a cobertura de código dos testes, aqui Você pode encontrar um guia breve sobre como usar o Jest, o Travis CI e o Coveralls para coletar e exibir essas informações.

Então, aqui está o conteúdo do arquivo .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

Aqui terminam as ações executadas para todos os ramos do repositório e para pull requests.

▍Implantação

Partindo da suposição de que todos os testes automatizados foram concluídos com sucesso, podemos, embora não seja obrigatório, implantar o código no servidor de produção. Como queremos fazer isso apenas para o código do ramo master, damos instruções apropriadas ao sistema nas configurações de implantação. Antes de tentar usar em seu projeto o código que abordaremos a seguir, gostaria de avisá-lo de que você deve ter um script real chamado para a implantação.

deploy:
  # Compilar o contêiner Docker e enviá-lo para o Docker Hub
  provider: script
  script: bash deploy.sh
  on:
    branch: master

O script de implantação resolve duas tarefas:

  • Compilação, tagging e envio da imagem para o Docker Hub usando a ferramenta CI (neste caso, o Travis CI).
  • Carregamento da imagem no servidor, parada do contêiner antigo e início do novo (neste caso, o servidor está na plataforma DigitalOcean).

Primeiro, precisamos configurar o processo automático de compilação, tagging e envio da imagem ao Docker Hub. Tudo isso é muito parecido com o que já fizemos manualmente, exceto que aqui precisamos de uma estratégia para atribuir tags únicas às imagens e automatizar o login. Tive dificuldades com alguns detalhes do script de implantação, como a estratégia de tagging, login, codificação de chaves SSH, e estabelecimento de conexão SSH. Mas, felizmente, meu namorado é muito bom com bash, assim como com muitas outras coisas. Ele me ajudou a escrever este script.

Então, a primeira parte do script é enviar a imagem para o Docker Hub. Fazer isso é bem simples. O esquema de tagging que usei implica em combinar o hash git e a tag git, se existir. Isso garante que uma tag única seja criada e facilita a identificação da compilação da qual ela se baseia. DOCKER_USERNAME e DOCKER_PASSWORD — são variáveis de ambiente personalizadas que podem ser definidas através da interface do Travis CI. O Travis CI processará automaticamente os dados secretos para que não caiam em mãos erradas.

Aqui está a primeira parte do script deploy.sh.

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

IMAGE="<username>/<repository>"                             # Образ 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}

A parte dois do script depende totalmente do tipo de host que você está usando e de como a conexão está organizada. No meu caso, como estou usando a Digital Ocean, os comandos para se conectar ao servidor são doctl. Ao trabalhar com a AWS, usaremos a ferramenta aws, e assim por diante.

Configurar o servidor não foi especialmente difícil. Assim, configurei um droplet baseado na imagem básica. Vale notar que o sistema que escolhi requer a instalação manual do Docker uma única vez e o início manual do Docker uma única vez. Para instalar o Docker, usei o Ubuntu 18.04, portanto, se você também usar o Ubuntu, para fazer o mesmo, pode simplesmente seguir este guia simples.

Não estou falando aqui sobre comandos específicos para o serviço, pois esse aspecto pode variar bastante em diferentes casos. Apenas apresentarei um plano geral de ação a ser realizado após a conexão via SSH ao servidor onde o projeto será implantado:

  • É preciso encontrar o contêiner que está em execução e pará-lo.
  • Em seguida, é preciso iniciar um novo contêiner em segundo plano.
  • Você precisará definir a porta local do servidor para 80 — isso permitirá acessar o site em um endereço como example.com, sem especificar a porta, em vez de usar um endereço como example.com:5000.
  • E, finalmente, é preciso remover todos os contêineres e imagens antigos.

Aqui está a continuação do script.

# Найти 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

Algumas coisas a serem observadas

Talvez, ao se conectar ao servidor via SSH do Travis CI, você veja um aviso que impedirá a continuação da instalação, pois o sistema estará esperando a resposta do usuário.

A autenticidade do host '<hostname> (<IP address>)' não pode ser estabelecida.
A impressão digital da chave RSA é <key fingerprint>.
Você tem certeza de que deseja continuar a conexão (sim/não)?

Descobri que a chave de string pode ser codificada em base64 para que seja possível trabalhar com ela de forma conveniente e segura. Na fase de instalação, é possível decodificar a chave pública e registrá-la no arquivo known_hosts para evitar o erro mencionado acima.

echo <public key> | base64 # exibe <a chave pública codificada em base64>

Na prática, esse comando pode parecer assim:

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

E é assim que fica o que ela gera — uma string codificada em base64:

MTIzLjQ1LjY3Ljg5IHNzaC1yc2EgQUFBQUIzTnphQzF5YzJFQUFBQUJJd0FBQVFFQWtsT1Vwb0RIcmZIWTE3U2JybVRJcE5MVEdLOVRqb20vQldEU1UKR1BsK25hZnpsSERUWVc3aGRJNHlaNWV3MThKSDRKVzlqYmhVRnJ2aVF6TTd4bEVMRVZmNGg5bEZYNVFWa2JQcHBTd2cwY2RhMwpQYnY3a09kSi9NVHlCbFdYRkNSK0hBbzNGWFJpdEJxeGlYMW5LaFhwSEFac01jaUxxOFY2UmpzTkFRd2RzZE1GdlNsVksvN1hBCnQzRmFvSm9Bc25jTTFROXg1KzNWMFd3NjgvZUlGbWIxenVVRmxqUUpLcHJyWDg4WHlwTkR2allOYnk2dncvUGIwcndlcnQvRW4KbVorQVc0T1pQblRQSTg5WlBtVk1MdWF5ckQyY0U4NlovaWw4YitndzNyMysxbkthdG1Ja2puMnNvMWQwMVFyYVRsTXFWU3NieApOclJGaTl3cmYrTTdRPT0geW91QGV4YW1wbGUuY29tCg==

Aqui está o comando mencionado anteriormente

install:
  - echo  | base64 -d >> $HOME/.ssh/known_hosts

A mesma abordagem pode ser usada com a chave privada ao estabelecer uma conexão, pois você pode precisar da chave privada para acessar o servidor. Ao trabalhar com a chave, você só precisa garantir seu armazenamento seguro em uma variável de ambiente do Travis CI, e que ela não seja exibida em nenhum lugar.

Outra coisa a se notar é que pode ser necessário executar todo o script de implantação apresentado como uma única linha, por exemplo — usando doctl. Isso pode exigir alguns esforços adicionais.

doctl compute ssh  --ssh-command "todas as comandos estarão aqui && aqui"

TLS/SSL e balanceamento de carga

Depois que fiz tudo o que foi mencionado acima, o último problema que encontrei foi que o servidor não tinha SSL. Como estou usando um servidor Node.js, para fazer com que funcione o proxy reverso Nginx e o Let’s Encrypt, é preciso passar um bom tempo arrumando.

Eu realmente não queria realizar todas essas configurações de SSL manualmente, por isso apenas criei um balanceador de carga e registrei suas informações no DNS. No caso da DigitalOcean, por exemplo, criar um certificado autoassinado que se atualiza automaticamente no balanceador de carga é um procedimento simples, gratuito e rápido. Essa abordagem também tem a vantagem adicional de permitir que seja muito fácil configurar o SSL em vários servidores atrás do balanceador de carga, permitindo que os próprios servidores não 'se preocupem' com o SSL, mas ainda assim utilizem, como de costume, a porta 80. Portanto, configurar o SSL no balanceador de carga é muito mais simples e conveniente do que métodos alternativos de configuração de SSL.

Agora, você pode fechar no servidor todas as portas que aceitam conexões de entrada, exceto a porta 80, usada para comunicação com o balanceador de carga, e a porta 22 para SSH. Como resultado, qualquer tentativa de acessar o servidor diretamente por quaisquer portas, exceto essas duas, falhará.

Resultados

Depois que fiz tudo o que descrevi neste material, eu já não tinha medo da plataforma Docker ou dos conceitos de cadeias CI/CD automatizadas. Eu consegui configurar uma cadeia de integração contínua, onde o código é testado antes de ser enviado para produção e é implantado automaticamente no servidor. Tudo isso ainda é relativamente novo para mim, e estou certa de que há maneiras de melhorar meu fluxo de trabalho automatizado e torná-lo mais eficiente. Portanto, se você tiver ideias a esse respeito, me deixe saber. Espero que este artigo tenha ajudado você em seus negócios. Quero acreditar que, ao lê-lo, você aprendeu tanto quanto eu aprendi enquanto lidava com tudo o que descrevi. No nosso

P.S. marketplace , há uma imagem , que é instalada com um clique. Você pode verificar o funcionamento dos contêineres em Docker. Todos os novos clientes recebem 3 dias grátis para testes. VPSVocê está utilizando tecnologias CI/CD em seus projetos?

Prezados leitores! RabbitMQ. Parte 1. Introdução. Erlang, AMQP

Criação de uma cadeia CI/CD e automação do trabalho com Docker

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster