A maioria dos projetos hoje em dia são desenvolvidos para diversos ambientes de trabalho (homolog, staging, production). E junto com esses ambientes temos a preocupação com a infraestrutura que o projeto vai utilizar, além do Framework utilizado no front-end para usabilidade e visualização de conteúdo.
Seguindo nesse raciocínio vamos falar sobre como utilizar variável de ambiente em um projeto que utiliza ReactJS, Docker e AKS, fazendo uma configuração simples para conseguir consumir a URL de uma API diferente de acordo com o ambiente em que o usuário está.
Após criar o projeto base com o npx create-react-app my-app
vamos criar uma pasta onde ficará as configurações de variáveis para cada ambiente.
environments/base.js
export default {
api: 'http://localhost:5000/api'
}
O base.js
é um arquivo inicial com o proposito de ser utilizado se nenhum outro arquivo ambiente for detectado pelas configurações.
environments/Homolog.js
export default {
api: 'http://suaapi.hlg.seudominio.com.br/api',
};
environments/Staging.js
export default {
api: 'http://suaapi.stg.seudominio.com.br/api',
};
environments/Production.js
export default {
api: 'http://suaapi.prd.seudominio.com.br/api',
};
Agora para finalizar as configurações das variáveis de ambiente vamos criar um último arquivo.
environments/index.js
import base from './base';
if (window.ENV) {
localStorage.setItem('@environment', window.ENV);
delete window.ENV;
}
const envClient = localStorage.getItem('@environment');
const environments = envClient || 'base';
const env = require('./' + environments).default;
export default {
...base,
...env,
}
Nessa configuração verificamos se existe algum valor em window.ENV
se existir valor salvamos ele no localStorage
e deletamos o window.ENV
, depois recuperamos esse valor salvo no localStorage
para utiliza-lo e caso esse valor não exista utilizamos 'base'
.
Ao final da configuração criamos uma nova importação utilizando require
onde ela importa o arquivo correto utilizando a variável environments
que pode conter o valor do localStorage
ou 'base'
e na conclusão exportamos as variáveis base
e env
onde teremos as informações necessárias para utilizar mais tarde.
Seguindo na configuração de variáveis de ambiente eu fiz uma alteração no App.js
, essa alteração é simplesmente para exibir a variável env.api
que vai ser consumida das configurações que fizemos anteriormente na pasta environments.
App.js
import React from 'react';
import logo from './logo.svg';
import env from './environments';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>{env.api}</p>
</header>
</div>
);
}
export default App;
E para finalizar a configuração inicial e antes de partirmos para a criação da imagem do Docker e as configurações .YAML do Kubernetes, faremos algumas modificações na pasta public
.
Primeiro vamos criar um novo arquivo .js dentro dela.
config.js
window.ENV = "Homolog"
Dentro desse arquivo temos uma configuração do window.ENV
que utilizamos para leitura dentro do environments/index.js
e que futuramente vai ser alterada via Kubernetes.
Logo após a criação desse arquivo vamos adicionar mais um script dentro do arquivo index.html
que fica na pasta public.
index.html
<script type="text/javascript" src="%PUBLIC_URL%/config.js"></script>
Essa alteração é para o projeto conseguir consumir o arquivo config.js
após o build do projeto.
Configuração de build e Kubernetes
Antes de criar a imagem do projeto no Docker vamos primeiro executar o build do próprio ReactJS, o que vai facilitar a criação da imagem no Docker.
npm run build / yarn build
Para criação da imagem do Docker o arquivo Dockerfile
ficará da seguinte maneira:
Dockerfile
# Stage 1
FROM nginx:1.17
# Stage 2
COPY build/ /usr/share/nginx/html
Além de já utilizar o build que foi feito pelo ReactJS anteriormente, utilizamos o nginx para rodar o html do projeto. Vale lembrar que o arquivo .dockerignore
não deve conter a pasta build, porque se não ocorrerá um erro quando a imagem for criada.
Seguiremos para criação da imagem do Docker executando os comando na sequencia:
1 - Criando a imagem do projeto
docker build -t react-docker-aks .
2 - Criação do registro no Docker local
docker run -d -p 5000:5000 --restart=always --name registry registry:2
3 - Criação de tag para referencia da imagem
docker tag react-docker-aks localhost:5000/react-docker-aks
4 - Fazendo o push da imagem para o Docker local
docker push localhost:5000/react-docker-aks
Obs.: é importante lembrar que para executar os comandos acima é necessário ter o Docker Desktop instalado na máquina.
E para finalizar criaremos os arquivos .YAML que são utilizados pelo Kubernetes para configuração dos clusters.
deployment.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: react-docker-aks
labels:
app: react-docker-aks
data:
config.js: "window.ENV = \"Homolog\";"
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: react-docker-aks
spec:
replicas: 1
selector:
matchLabels:
app: react-docker-aks
template:
metadata:
labels:
app: react-docker-aks
spec:
containers:
- name: react-docker-aks
image: localhost:5000/react-docker-aks
imagePullPolicy: Always
ports:
- containerPort: 80
volumeMounts:
- name: config-js
mountPath: /usr/share/nginx/html/config.js
subPath: config.js
volumes:
- name: config-js
configMap:
name: react-docker-aks
restartPolicy: Always
---
kind: Service
apiVersion: v1
metadata:
name: react-docker-aks
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 31000
selector:
app: react-docker-aks
Na criação dos arquivos .YAML utilizamos uma estrutura padrão de configuração adicionando apenas alguns métodos que serviram para leitura e configuração do arquivo config.js
que está na pasta public do projeto. São eles:
No ConfigMap
adicionei
data:
config.js: "window.ENV = \"Homolog\";"
No Deployment
dentro de spec containers
volumeMounts:
- name: config-js
mountPath: /usr/share/nginx/html/config.js
subPath: config.js
E a criação do volumes dentro do spec
volumes:
- name: config-js
configMap:
name: react-docker-aks
Foi uma escolha minha criar todas as configurações dentro do arquivo deployment.yaml
mas da certo criando os arquivos separados em configmap.yaml
, deployment.yaml
e service.yaml
, e depois criando o kustomization.yaml
para juntar todos eles.
Para simular outros ambientes eu criei mais dois arquivos deployment.yaml
o deployment-staging.yaml
e deployment-production.yaml
que tem o mesmo conteúdo do primeiro só modificando namespace, o valor do window.ENV e criando uma outra porta pro service.
deployment-staging.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: react-docker-aks-stg
labels:
app: react-docker-aks-stg
data:
config.js: "window.ENV = \"Staging\";"
--------
kind: Deployment
apiVersion: apps/v1
metadata:
name: react-docker-aks-stg
spec:
replicas: 1
selector:
matchLabels:
app: react-docker-aks-stg
template:
metadata:
labels:
app: react-docker-aks-stg
spec:
containers:
- name: react-docker-aks-stg
image: localhost:5000/react-docker-aks
imagePullPolicy: Always
ports:
- containerPort: 80
volumeMounts:
- name: config-js
mountPath: /usr/share/nginx/html/config.js
subPath: config.js
volumes:
- name: config-js
configMap:
name: react-docker-aks-stg
restartPolicy: Always
--------
kind: Service
apiVersion: v1
metadata:
name: react-docker-aks-stg
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 31001
selector:
app: react-docker-aks-stg
deployment-production.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: react-docker-aks-prd
labels:
app: react-docker-aks-prd
data:
config.js: "window.ENV = \"Production\";"
--------
kind: Deployment
apiVersion: apps/v1
metadata:
name: react-docker-aks-prd
spec:
replicas: 1
selector:
matchLabels:
app: react-docker-aks-prd
template:
metadata:
labels:
app: react-docker-aks-prd
spec:
containers:
- name: react-docker-aks-prd
image: localhost:5000/react-docker-aks
imagePullPolicy: Always
ports:
- containerPort: 80
volumeMounts:
- name: config-js
mountPath: /usr/share/nginx/html/config.js
subPath: config.js
volumes:
- name: config-js
configMap:
name: react-docker-aks-prd
restartPolicy: Always
--------
kind: Service
apiVersion: v1
metadata:
name: react-docker-aks-prd
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
protocol: TCP
nodePort: 31002
selector:
app: react-docker-aks-prd
Para executar o Kubernetes no Docker Desktop é necessário ativar-lo e também é preciso ter o Minikube instalado para executar os comandos que virão na sequencia.
Executando os comandos
1 - Criando o contexto padrão para o cluster do Kubernetes
kubectl config use-context docker-desktop
2 - Criando o serviço Kubernetes
kubectl apply -f deployment.yaml
3 - Serviço do ambiente staging
kubectl apply -f deployment-staging.yaml
4 - Serviço do ambiente production
kubectl apply -f deployment-production.yaml
Os ambientes ficaram disponivéis nas URLs:
HLG
http://localhost:31000/
E assim se concluí o projeto e todas as configurações realizadas para conseguir ler uma variável de ambiente após o build do ReactJS via Kubernetes.
O projeto todo pode ser acessado e baixado no meu github: https://github.com/felipedesenna/react-docker-aks
Top comments (0)