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.
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 e .
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 . Este é um projeto web no qual estou trabalhando, destinado a fazer anotações. No início, tentei criar um , ou apenas um aplicativo frontend sem servidor, para aproveitar as capacidades padrão de hospedagem e implantação de projetos que o oferece. À 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 guia sobre autenticação full-stack.
Conversei com , 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. 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 para repositórios git, ou um registro 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:
- Instale .
- Cadastre-se em .
Depois disso, você pode verificar se o Docker CLI está funcionando, executando o seguinte comando para verificar a versão do Docker:
docker -vEm seguida, faça login no Docker Hub, digitando, quando solicitado, seu nome de usuário e senha:
docker loginPara 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 imagesEsse 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
Modelo
Construindo uma imagem a partir de um Dockerfile
Modelo
Tagueando uma imagem
Modelo
Listando as imagens
O contêiner
Executando um contêiner baseado na imagem
Modelo
Enviando a imagem para o registro
Modelo
Baixando a imagem do registro
O contêiner
Listando os contêineres
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:
- — Este comando inicia o arquivo. Ele especifica a imagem base na qual o contêiner será construído.
- — Copiando arquivos de uma fonte local para o contêiner.
- — Definindo o diretório de trabalho para os comandos seguintes.
- — Executando comandos.
- — Configurando a porta.
- — 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 startDependendo 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 , 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.0Se 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 . Como servidor — .
É 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 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 da tarefa. Aqui estão esses eventos, apresentados na ordem em que ocorrem:
apt addonscomponents do cachebefore_installinstallbefore_scriptscriptbefore_cacheafter_success ou after_failurebefore_deploydeployafter_deployafter_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, 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 testAqui 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: masterO 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 . 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 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 comoexample.com, sem especificar a porta, em vez de usar um endereço comoexample.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 -fAlgumas 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" | base64E é 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_hostsA 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 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 No nosso
P.S. marketplace , que é instalada com um clique. Você pode verificar o funcionamento dos contêineres em . Todos os novos clientes recebem 3 dias grátis para testes. Você está utilizando tecnologias CI/CD em seus projetos?
Prezados leitores! RabbitMQ. Parte 1. Introdução. Erlang, AMQP
Fonte: habr.com
