deployando site estático no S3 pt1: CDK's BucketDeployment sucks

Você tem lá um CDK para um site estático, s3, cloudfront, cert manager etc. Agora precisa fazer um deploy, e naturalmente busca uma solução na mesma vibe, o BucketDeployment.

E até que funciona, faz até invalidação com CloudFront!

Porém chega uma hora que você percebe: isso leva mais tempo que deveria.

Aí olhando no código (e explorando o CloudFormation no console) percebe que faz muito mais do que você imaginava, cria um CRD, que cria (dentre outras coisas) um bucket e um lambda, que é o que faz efetivamente o trabalho de copiar para o seu bucket de destino.

Então se copia 1 vez para um bucket temporário, e depois para o bucket correto. Para mais infos ver o código do lambda.

O que é claramente um desperdício de tempo.

A solução é simplesmente usar a cli, usando aws s3 sync para copiar os arquivos se você quiser, preferencialmente os novos, e deletar os que não quer (os que não serão mais usados).

Ficaria algo como

1
aws s3 sync out s3://$SEU_BUCKET --delete

Se quiser checar antes de commitar com o deploy (recomendado), rode com --dryrun antes, ele vai listar os arquivos como por exemplo:

1
2
(dryrun) upload: out/_next/static/3BRZtz_wC32BCqy0h8gHL/_buildManifest.js to s3://$BUCKET_NAME/_next/static/3BRZtz_wC32BCqy0h8gHL/_buildManifest.js
(dryrun) delete: s3://$BUCKET_NAME/_next/static/99ixjLUK2BVi2N5LwU41p/_buildManifest.js

yay!!?! not so fast

Tudo as mil maravilhas, porém estranhei que a lista de arquivos era sempre muito maior do que esperava. Não mudei nada no meu site estático, por que está querendo subir todos os arquivos?!

Bom, aparentemente eles checam o timestamp e o tamanho do arquivo. Se você está fazendo um build novo, o timestamp dos arquivos também vai ser novo. Não sei se tem um jeito de falar pra ferramenta de build pra não mexer nos arquivos novos, e aí em CI cachear esses arquivos tal que seu timestamp não mude. E se tem, não sei se quero seguir nessa rota.

Uma outra sugestão é falar para ignorar timestamps e usar apenas o tamanho do arquivo, com a flag --size-only.

Ah, mas se eu trocar uma string de “CAVALO” para “CAMELO”, que tem o mesmo tamanho, o que acontece? Não vai funcionar, sinto muito.

Além desse exemplo trivial, ainda tem o caso levantado numa issue do Github onde o seu index.html não muda de tamanho, especialmente no caso de SPA onde o html é o mesmo, só mudando o hash dos javascript inclusos (por ex foo.ABC.js vira foo.JKL.js).

Nesse caso acho mais fácil simplesmente dar um aws s3 cp no index.html.

checksum no s3 sync? não pra você

Idealmente seria possível usar um checksum como gerado via MD5 para checar o contéudo, é uma issue que existe desde 2014 (FELIZ BODAS DE ESTANHO!).

A implementação existe em layers inferiores, mas não chegou ainda na aws s3, e sabe-se-lá quando vai chegar.

Me perguntei como ferramentas como hugo fazendo deploy. Aparentemente segundo a documentação o hugo checa o md5 dos arquivos, aqui o código.

“Ah mas como pega o MD5? Tem que baixar o arquivo?”. Não, tal como dito anteriormente e segundo esse comentário no código do hugo, a API do S3 já retorna isso.

O que me faz pensar que deve ser mais fácil só usar a cli do hugo para deploys ao invés de usar a cli da aws :^)

bônus

Ainda tem um grande detalhe não necessariamente relacionado que não falei: você não pode só usar --delete e seguir com seu dia, já que possivelmente há alguém com o site aberto, com o _buildManifest (do nextjs no caso, basicamente um mapa de rotas para filenames, apesar de que ideias similares existem em outros frameworks) apontando para certos arquivos em caso de lazy load, que por sua vez não vão existir, quebrando a navegação do pobre coitado!

Então idealmente a solução seria:

  1. Vê os arquivos que vão ser deletados
  2. Muda a expiração deles pra sei lá, daqui 1 semana
  3. Copia pro bucket os arquivos novos (s3 sync)
  4. Muda o seu código/do framework para quando carregar um chunk inexistente, refreshar a página

BREAKING NEWS: fui informado que o NextJS já faz isso, mas não chequei. Trust but don’t verify.

Inspirações

Stop Using the CDK S3 Deployment Module | by Riccardo Giorato | AWS in Plain English.