Havia uma coisa que me incomodava em um projeto que eu estava envolvido, era o fato de que aparentemente precisávamos gerar uma imagem específica para ambiente que fosse rodar o front-end.
Mas porque tinham de fazer assim?
O front-end era feito com React e quando se fazia o comando npm run build
a variável utilizada para informar o endereço da API que o front-end deveria consumir era transformada em um dado hardcoded no JavaScript gerado.
Ao menos até agora foi a única coisa que encontramos que atrapalhava nisso :P
Exemplo:
Digamos que o arquivo .env fosse:
REACT_APP_API ="https://api.somatorio.org"
E o Dockerfile fosse:
FROM node:12-slim AS build
WORKDIR /usr/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:1.17.6-alpine
COPY --from=build /usr/app/build/ /usr/share/nginx/html/
CMD [ "nginx", "-g", "daemon off;"]
Para cada ambiente onde a api não fosse a mesma teríamos de fazer uma imagem em separado alterando o .env, certo?
E tudo o que eu e minhas colegas vimos sobre esse assunto terminava ou em “é assim que a gente faz mesmo” ou em alguma solução que parecia muito mais complexa do que deveria ser…
E como resolveram isso?
Usamos sed ;)
Ok, eu preciso que tu me explique um pouco melhor isso
Como eu disse antes, tudo o que a gente encontrava sobre react em container envolvia ter múltiplas imagens ou algum script complexo e que envolvia alterar a aplicação…
Então, certo dia me veio uma idéia:
E se a gente definir essa variável com algum dado e mudar ele com sed no javascript quando o container subir?
Fizemos um teste bem simples fazendo um build desse react e brincando com o sed na linha de comando mesmo e… funcionou! :D
Então fizemos um script de entrypoint bem simples para alterar o valor esperado
#!/bin/sh
find /usr/share/nginx/html/static/js -type f -print0 | xargs -0 sed -i s,VAR_URL_API,$URL_API,g
exec "$@"
E alteramos o valor da variável no .env para VAR_URL_API durante o build da imagem.
Porque não alteramos direto no .env da fonte? A idéia era não alterar nada do que o pessoal de desenvolvimento do software tinha feito, além disso a gente garante que vai estar esse valor ali sempre
Outra coisa que fizemos foi colocar um ENV com um valor default para essa env var (apontando pra api de dev)
No final o Dockerfile ficou assim:
FROM node:12-slim AS build
WORKDIR /usr/app
COPY package*.json ./
RUN npm install
COPY . .
RUN echo 'REACT_APP_API ="VAR_URL_API"' > .env.production && \
npm run build
FROM nginx:1.17.6-alpine
ENV URL_API="https://api-dev.somatorio.org"
COPY --from=build /usr/app/build/ /usr/share/nginx/html/
COPY entrypoint.sh /usr/local/bin/
ENTRYPOINT [ "/usr/local/bin/entrypoint.sh" ]
CMD [ "nginx", "-g", "daemon off;"]
Depois de construída a imagem, basta subir ela com docker run -e URL_API="https://endereco.da.api" -p 80:80 nomedaimagem
(ou usando a ferramenta de orquestração que achares melhor) :)