CDN de alta disponibilidade na AWS com S3, CloudFront e Route53
Distribuição de conteúdo ao redor do mundo com baixa latência.
Este é um guia sem enrolações (prometo entrar no detalhe apenas do que for essencial) sobre como provisionar uma rede de distribuição de conteúdo (CDN) na AWS. Os passos são executados via console (GUI/interface) e as capturas de tela tendem a ficar obsoletas com o passar do tempo, podendo não representar o estado atual da interface à medida que as soluções evoluem.
Se preferir utilizando Iac (Infrastructure as Code) com Terraform, confira este artigo.
Pressuponho que:
- já possua uma conta na AWS, se não tiver crie e logo de início ganhe 12 meses de nível gratuito (as ferramentas envolvidas no artigo são privilegiadas);
- tem um domínio (hosted zone) cadastrado no Route53 (caso preferir utilizar o seu).
- está buscando distribuir conteúdo de maneira replicada pelo mundo e com baixa latência. Caso os usuários forem de uma única região e não existir preocupação com futuras expansões, é possível utilizar apenas o S3 com a opção static website.
O que são conteúdos estáticos?
São arquivos em que o conteúdo não é criado dinamicamente, embora possa mudar com determinada frequência, em sua essência ele permanecerá o mesmo até a próxima alteração e, no momento que ela (alteração) ocorrer podemos realizar diversas operações para garantir que o novo conteúdo seja distribuído para os clientes através de práticas como a invalidação de cache.
Exemplos de arquivos estáticos: Imagens, aplicações SPAs (já que são compostas de arquivos de texto/scripts), tipografias, vídeos (você até pode, mas o tipo da distribuição do CloudFront deste artigo não tem este propósito — assunto para outra ocasião) e outros.
CDN
Content Delivery Network (Rede de distribuição de conteúdo) — tem como principal motivo contribuir para a melhora do tempo de carregamento de páginas e aumentar a disponibilidade do conteúdo ao redor do mundo, normalmente esta inclui diversos servidores de borda (edge) que são próximos do usuário (e isto é o que garante a baixa latência).
S3
O S3 é o serviço da AWS voltado ao armazenamento de arquivos, nele criamos diversos buckets (baldes) que são os espaços onde iremos realizar o upload. Um bucket pode ser organizado por pastas e conter configurações de vida útil de um objeto/arquivo (tais como expiração), permissões, CORS e uma infinidade de outros.
CloudFront
O CloudFront é um serviço vital para inúmeros outros dentro da nuvem da AWS, muitas das vezes você o utiliza sem perceber. É ele quem garante a disponibilidade ao redor do mundo e melhores taxas de latência com base na localização do cliente. Embora este artigo trate de arquivos estáticos, não é só para isto que o CloudFront serve, podendo distribuir APIs através de Lambda@Edge, transmissão ao vivo e sob demanda de vídeo, distribuição de atualizações para dispositivos IoT e outros.
Podemos adicionar um nome de domínio para uma distribuição (nome dado a instância do CloudFront) utilizando o Route53 (serviço para gerenciamento de DNS da AWS), configurar regras de proxy adicionando uma Lambda à frente para controlar CSP — Content Security Policies [assunto para próximos artigos, mas se tiver pressa, veja esse artigo do Jake Wells], revalidação de cache, monitorar tráfego e uma infinidade de cenários.
Antes de provisionar qualquer recurso cloud é importante analisar os custos envolvidos para evitar surpresas, se estiver em uma conta de nível gratuito trate de certificar quais os limites.
Definição de preço
A AWS oferece no nível gratuito (de 12 meses), a cada mês: 50 GB de transferência de dados para fora, 2 milhões de solicitações HTTP ou HTTPS e 2 milhões de invocações do CloudFront Functions. Para mais detalhes, consulte a definição de preço.
Se não estiver no nível gratuito, faça uma simulação utilizando a calculadora de preços.
Cenário hipotético de um CloudFront com as seguintes características e seus respectivos custos:
- Região us-east-1 (N. Virginia)
- 10 GB por mês de tráfego de saída para a internet = 0.85 USD
- 10 GB por mês de transferência para o servidor de origem (solicitações POST e PUT) = 0.20 USD
- 100.000 requisições HTTPS por mês = 0.10 USD
0.85 USD + 0.20 USD + 0.10 USD = 1.15 USD (Custo total por mês)
Vamos lá…
Meu console se encontra em inglês para facilitar o entendimento e evitar traduzir alguns termos técnicos (mesmo que sua conta estiver em português é comum o console não ser 100% traduzido e ainda aparecer termos em inglês).
S3 Bucket
O S3 é o local onde vamos armazenar os conteúdos da CDN, para isto precisamos criar um bucket (balde). Localize o S3 na busca de serviços:
Clique em Create Bucket:
Com base em minha experiência em determinado momento você pode desejar ativar alguns recursos no bucket que dependem de requisitos que sigam boas práticas de nomenclatura, como o Transfer acceleration e para isto obrigatoriamente o nome não pode conter .
Mais sobre convenção de nomes:
Seguindo as boas práticas, vamos utilizar hífen —
para separar as palavras, preencha os dados para a criação do bucket:
- Bucket name: deve ser um nome único em toda a AWS;
- AWS Region: como o CloudFront ficará à frente do nosso bucket e esta será a única maneira de acessar os conteúdos, preferi utilizar
us-east-1
porque os custos são inferiores à São Paulosa-east-1
— Mais sobre custos do S3. (dependendo de seus planos, verifique a legislação quanto ao local de armazenamento dos dados); - Block Public Access settings for this bucket: mantenha o padrão;
- Bucket Versioning: fica a critério, isto criará novas versões caso o documento enviado tenha o mesmo nome e facilitará rollback em caso de sobrescritas acidentais, em contrapartida tende a aumentar o consumo de armazenamento do bucket ao longo do tempo se não for configurada uma rotina automática de limpeza;
- Mantenha as demais opções sem alterar e crie o bucket clicando em Create bucket.
Após isto seu bucket estará criado:
No S3 por enquanto não há mais o que fazer, já existe um local para armazenar os arquivos. O próximo passo é criar a distribuição do CloudFront.
Distribuição do CloudFront
Localize o CloudFront na busca de serviços:
Clique em Create Distribution:
Agora a lista de configurações começa a ficar um pouco extensa, esta etapa é de extrema importância, resolvi numerar os passos iniciais para facilitar o entendimento:
- Origin domain (1): é o bucket do S3 a ser utilizado pelo CloudFront, pesquise pelo nome criado na seção anterior, no meu caso é
tiagoboeing-cdn-article.s3.us-east-1.amazonaws.com
; - Origin path: é opcional, ao deixar em branco o CloudFront estará utilizando a raiz do bucket como caminho relativo, mas se preferir é possível especificar uma determinada subpasta como raiz;
- Name (2): por padrão este campo será preenchido com o nome do bucket, defina o valor que preferir para facilitar a identificação da distribuição, costumo utilizar o domínio associado à mesma;
S3 bucket access: como deixamos nosso bucket privado (de maneira proposital para evitar acesso direto à ele), vamos configurar uma política que permita ao CloudFront ler os arquivos que lá estão;
- (3) — Marque Yes use OAI (bucket can restrict access to only CloudFront);
- (4) — Vamos criar a access identity, clique em Create new OAI, preencha com o nome desejado conforme o padrão que preferir, costumo utilizar o prefixo sugerido (
access-identity-
) + domínio da CDN, clique em criar e a Origin access identity será preenchida automaticamente.
- (5) — Marque a caixa Bucket policy → Yes, update the bucket policy.
Para facilitar, um resumo apenas do que alterei mais abaixo:
- Em Default cache behavior — Viewer → Viewer protocol policy: Redirect HTTP to HTTPS;
- Em Settings — Alternate domain name (CNAME): adicionei o domínio que pretendo usar e vou configurar no Route53 posteriormente;
- Em Settings — Custom SSL certificate: clique em Request certificate e na nova aba será aberto o AWS Certificate Manager (o certificado SSL é gratuito), os passos são auto-guiados:
* Request a public certificate → em Fully qualified domain name coloque o domínio que irá utilizar na CDN → escolha como pretende verificar o domínio (se estiver configurado no Route53 use DNS validation pois a validação é automática) → Clique em Request;
* Via DNS: Após solicitar, acesse o certificado e em Domains clique em Create records in Route 53 → Create records. - Em Settings — Default root object: se for utilizar a CDN para hospedar páginas estáticas (SPAs) defina
index.html
- Em Settings — Description: opcionalmente preencha com a observação que preferir.
Crie a distribuição e aguarde, o status ficará como Deploying e isto pode levar alguns minutos.
Abaixo o resultado de todas as alterações realizadas para não restar dúvidas, em vermelho os locais modificados:
Após alguns minutos… Pronto! Temos a distribuição criada! 🚀
Clicando no título é possível verificar as configurações:
Criar registro no Route53 para o CloudFront
Como ao longo do artigo optei por utilizar o subdomínio cdn-article.tiagoboeing.com
para exemplo, resta apenas criar este registro no Route53. Copie o domínio de Distribution domain name (inclusive se ignorar esta etapa, este será o endereço de acesso da CDN).
O passo é opcional, mas leve em conta que ao utilizar o domínio padrão do CloudFront as alterações nas propriedades do domínio durante a criação da distribuição e o certificado não devem ser realizadas.
Vou ser breve nesta etapa.
Estou presumindo que já existe uma hosted zone configurada. Acesse o Route53 buscando na lista de serviços; Clique na Hosted zone do seu domínio e vá para Create record.
- Record name: coloque o subdomínio utilizado durante a criação do CloudFront, no meu caso
cdn-article
; - Record type: A — Routes traffic to an IPv4 address and some AWS resources;
- Marque a caixa de seleção Alias e escolha Route traffic to → Alias to CloudFront distribution
* E na caixa Choose distribution se tiver sorte tente localizar sua distribuição. (Aqui há uma incógnita, às vezes a AWS simplesmente não encontra a distribuição, por isso a dica de copiar a Distribution domain name anteriormente) — se não conseguir localizar pela caixa basta colar o valor. - Mantenha as demais opções com os valores padrões.
Hora da diversão, vamos aos testes
Recapitulando…
- Criamos o bucket no S3 para armazenar os arquivos da CDN;
- Criamos a distribuição do CloudFront, definimos um nome de domínio, solicitamos um certificado SSL e anexamos nela;
- Apontamos um subdomínio para a distribuição.
Vamos tentar acessar o subdomínio criado, no meu caso cdn-article.tiagoboeing.com
(para você estará inacessível pois removi após finalizar o artigo).
Sem pânico! Não há conteúdo no bucket do S3 e neste caso haverá erro mesmo, mas perceba que ao digitar http://
automaticamente será alterado o endereço para utilizar HTTPS.
Adicione qualquer arquivo no S3
Adicionei um arquivo HTML chamado index.html
para testar a propriedade Default root object que configuramos durante a criação do CloudFront. Basta arrastar e soltar o arquivo no bucket (não customizei nenhuma configuração, apenas fiz upload).
E… vamos testar novamente recarregando a página.
Tudo certo! A CDN está pronta para ser utilizada.
Por segurança vamos tentar acessar o S3 diretamente sem passar pelo CloudFront, o endereço será https://tiagoboeing-cdn-article.s3.us-east-1.amazonaws.com/index.html
e é esperado um erro de permissão, isto indica que o bucket realmente está privado e apenas acessível via domínio do CloudFront:
Invalidação de cache
O CloudFront possui um cache configurável, a distribuição que criamos utiliza as políticas padrões recomendadas, isto significa que o CloudFront entregará ao usuário o conteúdo que estiver em seu cache quando disponível e não expirado/invalidado. Esta é a razão pela qual ao realizar upload de um novo arquivo e/ou modificar um existente as alterações não são refletidas automaticamente, você precisar criar uma invalidação de cache!
No momento que uma invalidação for criada, assim que houver uma requisição para a distribuição o CloudFront verificará por novos arquivos e criará o cache novamente.
Esta foi a configuração de cache que utilizamos:
E aqui as políticas associadas a ela. Temos um TTL padrão de 24 horas (86.400 segundos).
Modifiquei o título do arquivo HTML para demonstrar o cache.
Realiza upload ao S3 e sobrescrito o index.html
existente… Ao voltar no browser e recarregar a página ainda visualizamos o conteúdo antigo:
O motivo? Bem! O santo cache. Vamos criar uma invalidação. Volte ao CloudFront e clique na distribuição, depois acesse a aba Invalidations:
Clique em Create invalidation → na caixa Add object paths é possível:
- escolher objetos (arquivos) individualmente:
index.html
,pasta/arquivo.txt
, etc; - invalidar tudo de uma pasta específica:
pasta/*
; - invalidar todo o conteúdo de todo o CloudFront:
/*
.
Como no S3 temos apenas um arquivo chamado index.html
e para exemplificar vou invalidar todo o conteúdo de todo o CloudFront informando: /*
.
Tente ser o mais restritivo possível, evite criar invalidações usando /*
pois isto tende a exigir maior tempo à medida que o conteúdo aumenta e fim do mês haverá uma surpresa ao verificar a fatura 😁, já que cada invalidação possui um custo.
Não há cobrança adicional para os primeiros 1.000 caminhos solicitados para invalidação a cada mês. Acima desse limite, será cobrado 0,005 USD por solicitação de invalidação de caminho.
Invalidação finalizada:
Agora é simples, basta voltar ao endereço da CDN, atualizar a página e o novo conteúdo será entregue ao cliente:
Ideias de próximos passos:
E talvez até mesmo artigo futuro… 🤔 O que acha?
- Automatize via CI/CD o fluxo de upload dos arquivos para o S3 e invalidação do cache do CloudFront, utilize-o para entregar suas funcionalidades e correções com agilidade e/ou testar as MRs/PRs durante o desenvolvimento;
- Configure a segurança utilizando Lambda@Edge para definir CSP — Content Security Policy. Duas ferramentas úteis para auxiliar na depuração: Mozila Observatory e Google CSP Evaluator;
- Configure a distribuição para navegar corretamente entre as rotas de um SPA;
- Crie uma stack IaC (Infrastructure as Code) e evite configurações manuais via console da AWS sempre que precisar de uma nova CDN, faça deploy em poucos minutos com apenas alguns comandos. Ferramentas que podem auxiliar: Terraform, Serverless Framework ou AWS CloudFormation. | UPDATE: Artigo criado, confira aqui!
Fique por dentro das novidades
- Se inscreva na newsletter do Medium para receber meus novos artigos;
- Se inscreva em meu canal do Youtube para acompanhar tutoriais.