7.6 Definindo o chart utilizado para execução local e na nuvem
Vamos definir um chart para executarmos a aplicação, inicialmente localmente, e posteriormente na nuvem da Oracle. Para isso, vamos criar o diretório chart na raíz do nosso projeto, e acrescentar nele Chart.yaml
, contendo o seguinte conteúdo:
Nele, definimos o nome do nosso chart (name: loja-virtual
) e sua versão (version: 1.0.0
), elaboramos uma descrição (description: Chart para implantação da loja virtual no Kubernetes
), definimos seu tipo como aplicação (type: application
) e informamos a versão da aplicação que ele instala (appVersion: 1.0
).
Uma boa prática consiste em definir um arquivo chamado .helmignore
dentro do diretório chart. Esse arquivo informa ao helm padrões de arquivos que devem ser ignorados. Cada linha desse arquivo deve conter um único padrão, tal como no arquivo .gitignore
dos repositórios git. Vamos usar o seguinte arquivo:
Nele podemos ver que diretórios e arquivos comuns às diversas IDEs existentes são ignorados, como por exemplo os diretório .vscode
, referente à IDE Visual Studio Code, e o diretório .idea
, referente à IDE IntelliJ, bem como arquivos comuns de backup (aqueles com extensão .bak e .swp) e arquivos de sistemas de controle de versão como o próprio .gitignore
.
Na sequencia, é necessário criar o subdiretório templates
dentro do diretório chart
, que como visto anteriormente, deve conter os templates utilizados para gerar os arquivos de recursos do Kubernetes.
Vamos inicialmente criar nosso primeiro deployment, no arquivo loja-deployment.yaml
. Ele terá o seguinte formato:
É interessante observar que na linha 4 definimos o nome do deployment (loja-virtual), e entre as linhas 6 e 12 definimos os labels dele, usando os labels recomendados pela documentação do Kubernetes (https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/). Os labels, como dito anteriormente, ajudam a classificar e agrupar os recursos.
Os mesmos labels são utilizados nas linhas 25-31, e são aplicados nesse caso aos containers criados pelo deployment. No exemplo temos apenas um container, com o nome loja (linha 35), que usa a imagem registry-local:5005/loja-virtual (linha 36) e somente tenta baixar a imagem do registry se ela não estiver presente ainda no cluster Kubernetes (IfNotPresent, na linha 37).
Nosso container permite a conexão externa ao POD por meio da porta 8080 (linha 40), por meio do protocolo TCP (linha 41), e a essa porta foi atribuído o nome arbitrário de http (linha 39). Para o deployment saber quais são os containers que são gerenciados por ele, definimos nas linhas 17-21 os labels que serão utilizados para selecionar os respectivos containers. No nosso caso, estamos usando apenas 4 labels, em vez das 6 definidas para os containers. Poderíamos usar todas as 6, ou qualquer número entre 1 e 5. O importante nesse caso é selecionar as labels que identifiquem univocamente os containers que devem ser gerenciados pelo deployment.
Com a definição desse deployment, podemos testar o deploy no cluster Kubernetes usando o Helm. Mas primeiro, é necessário realizar o build da imagem da aplicação, e seu envio para o registry (registry-local:5005
). Esses dois passos podem ser realizados pelo seguinte comando, o qual deve ser executado na raíz do projeto:
Na linha 1 usamos o comando build
do docker para criar a tag registry-local:5005/loja-virtual
, por meio do parâmetro -t
, e informamos que o contexto utilizado será o diretório atual (.
).
Já na linha 2, o comando push
é utilizado para enviar a imagem gerada para o registry. Com isso, nossa imagem poderá ser baixada pelo Kubernetes para gerar o container que definimos no deployment.
O arquivo Dockerfile presente na raiz é utilizado para formar a imagem base da nossa aplicação. Ela basicamente contém um servidor Tomcat, na versão 7.0, e o jdk8. A imagem que será efetivamente utilizada no cluster é gerada com base nela, e contém também a aplicação da loja virtual. Essa imagem é gerada pelo Jib.
Agora, é possível usar o Helm para realizar o deploy no kubernetes com o seguinte comando:
O comando install
é responsável por instalar um chart no cluster Kubernetes. Deve ser informado o diretório no qual está localizado o chart. No nosso exemplo, o diretório tem o nome chart
.
Vamos instalar o chart em um namespace chamado loja-virtual, definido pelo parâmetro -n
. Esse namespace ainda não existe, por isso, utilizamos o comando --create-namespace
que cria o namespace caso ele ainda não exista. O Helm criará uma nova release no Kubernetes, cujo nome loja-virtual
, é definido por meio do parâmetro --name-template
.
A saida desse comando será semelhante a essa:
Podemos observar que o status é deployed, indicando que o foi realizado o deploy no cluster Kubernetes. Isso nos indica que nosso deployment está correto. Podemos verificar o log do container com o comando a seguir:
O kubectl, como mencionado anteriormente é uma aplicação de linha de comando que permite interagirmos com o cluster Kubernetes. Utilizamos o comando logs para informar que queremos obter os logs do deployment loja (deployment/loja
), de maneira mais específica do container loja (-c loja
), que está localizado no namespace loja-virtual (-n loja-virtual
).
Para usar nossa aplicação no navegador, é necessário mapear a porta do contêiner em uma porta local da nossa máquina. Esse procedimento é realizado utilizando o comando a seguir:
Com esse comando, estamos mapeando a porta 8080 do contêiner na porta 8090 da nosso máquina. Desse modo, no navegador, conseguimos acessar nossa aplicação com o endereço http://localhost:8090.
//TODO: Explicar que falta o banco de dados
Como podemos observar, nosso arquivo de template ainda está estático, assim como os arquivos do Kubernetes que criamos na seção 7.3. Vamos ver agora 3 modos de deixar o arquivo mais dinâmico, com a utilização de valores definidos conforme necessidade.
Valores definidos no arquivo values.yaml
Podemos melhorar isso com a criação do arquivo values.yaml
dentro do diretório chart
. Esse arquivo, como mencionamos, será utilizado para definir chaves com valores-padrão que serão utilizadas e substituídas nos templates.
Inicialmente ele será assim:
Uma vez definido esses valores, podemos utilizá-los nos arquivos de templates. A utilização será realizada usando a seguinte sintaxe:
Por exemplo, podemos definir a porta utilizada no contêiner do seguinte modo:
Essa notação indica que deve ser utilizado o valor definido no arquivo values.yaml
(.Values) por meio da sub-chave port
, definida aninhada na chave service
(service.port
). Olhando novamente o arquivo values.yaml
vemos que esse valor é 8080:
Portanto, o resultado do template será containerPort: 8080
, que é exatamente o valor que queremos.
Valores definidos no arquivo charts.yaml
Outra substituição que podemos fazer, é utilizar informações do arquivo Chart.yaml. De modo análogo, podemos definir, por exemplo, o nome do continer do seguinte modo:
Nesse caso, dada a definição a seguir presente no arquivo Chart.yaml:
Teremos o seguinte arquivo resultante da substituição de valores no arquivo de template:
Valores definidos com named templates no arquivo _helpers.tpl
Um recurso interessante do Helm é a utilização de named templates
. Named templates são templates definidos em um arquivo, aos quais é atribuído um nome, e que podem ser utilizados em outros templates, de modo semelhante a uma função ou método em programação. É um modo de reutilizar código.
Podemos definir named templates no arquivo _helpers.tpl
, dentro do diretório templates
. A seguir, temos a definição do named template chart.name
:
No arquivo _helpers.tpl
, usamos sempre blocos que iniciam com {{
e são finalizados com }}
. Podemos definir comentários entre os símbolos /*
e */
.
A definição de um named template pode ser realizada com a palavra define, tal como na linha 4 do código anterior, no qual definimos o named template chart.name
. Podem ser usadas funções tal como na linha 5, onde são usadas as funções default
, trunc
e trimSuffix
. As funções disponíveis no Helm podem ser conferidas na documentação.
Na linha 5, estamos definindo que vamos utilizar o valor definido pela chave nameOverride, definida no arquivo values.yaml
. caso ela exista, caso contrário, o valor padrão (default) será o valor da chave Name
, presente no arquivo chart.yaml
. A seguir, o valor será utilizado como parâmetro para a função trunc
, por meio da utilização do pipe (|
).
A função trunc
retorna somente os N primeiros caracteres de um texto. No exemplo anterior, o valor de N
foi definido como 63
. A seguir, o valor obtido é passado como parâmetro para a função trimSuffix
, que remove o sufixo informado como parâmetro, no caso -
. O valor resultante, pode ser utilizado nos arquivos de templates com a palavra include, do seguinte modo:
O nosso arquivo _helpers.tpl completo ficará assim:
Podemos testar o template do deployment, com a substituição de variáveis com o seguinte comando:
Esse comando vai atualizar a versão do chart de acordo com as alterações que realizamos. Para acesarmos pelo navegador teremos que repetir o comando para mapear a porta do contêiner em uma porta da nossa máquina:
O próximo passo agora é definir o template para criar um serviço para nossa aplicação. Para isso, será criado o arquivo service.yaml
dentro do diretório templates
. Ele ficará do seguinte modo:
Note que assim como fizemos no caso do deployment, estamos também usando valores provenientes do arquivo values.yaml, tal como em:
Também são utilizados named templates como no caso a seguir:
Observe que podemos utilizar o named template como entrada para uma função. No exemplo apresentado, o named template chart.selectorLabels é usado como parâmetro para a função nident
, que realiza a identação colocando N
número de espaços antes do valor do parâmetro. No nosso caso, são 4 espaços.
Podemos atualizar novamente nossa release, com o comando já apresentado, e na sequencia realizar o mapeamento agora de uma porta do serviço para uma porta da nossa máquina:
Observe que o resultado prático foi o mesmo de fazer o mapeamento para o deployment, porém, se tivéssemos mais de uma réplica do deployment, ao acessarmos o endereço pelo navegador, poderíamos a cada momento ser atendidos por uma instância diferente da aplicação.
Essa é uma das vantagens de utilizar services, conforme explicado anteriormente.
Ainda falta uma peça nesse quebra-cabeça para que nossa aplicação funcione adequadamente, que é o banco de dados.
Como o banco de dados é uma dependência de nossa aplicação, podemos criar um subchart para implementar o banco. A vantagem de fazer isso é ter uma estrutura de arquivos mais organizada. Para criar o subchart do banco de dados, vamos criar o diretório charts/mysql dentro do diretório chart, e dentro dele vamos ter uma estrutura semelhante à do chart:
O arquivo Chart.yaml ficará assim:
Já o arquivo values.yaml será desse modo:
O arquivo _helpers.tpl terá o seguinte conteúdo:
E os arquivos db-deployment.yaml e db-service.yaml ficarão respectivamente assim:
Observe que nossa aplicação acessará o banco de dados por meio do nome do serviço, segundo nosso exemplo, esse nome será db
. E a porta será a 3306
.
Last updated