DEV Community

fabriciolfj
fabriciolfj

Posted on • Updated on

Spring boot, githubActions e argocd

CI/CD não é novidade no mundo do desenvolvimento de software, no entanto a entrega de manifestos kubernetes apartado da aplicação, é uma prática a ser seguida.
Esse artigo tem por objetivo demonstrar tal situação, através do action github e o argocd.
_Pré-requisito: ter noção sobre docker, kubernetes, java e terraform.

Breve explicação dos recursos utilizados neste exemplo

  • Spring boot: framework para aplicações java, que utiliza padrões de projeto para controlar a injeção de dependência, alem de prover objetos para solucionar diversos problemas. A aplicação é executa dentro do seu contexto, alem de possuir um webservice embarcado (modelo imperativo é o apache e reativo é o netty).
  • Terraform: utilizado para criar recursos/infraestrutura na nuvem ou local via código. Nesse artigo criaremos um cluster kubernetes utilizando terraform localmente, em conjunto com kind.
  • Argocd: ele inspeciona um repositório que possui os manifestos kubernetes, e caso ocorra alguma alteração, o mesmo os aplica. Em resumo ele cuida da entrega dos manifestos kubernetes dentro do cluster.
  • GithubActions: recurso do github que cuida do CI/CD. No nosso projeto utilizaremos para efetuar o deploy da aplicação, criação da imagem docker e atualização do repositório dos manifestos.
  • Helm: instalador de pacotes dentro do cluster kubernetes. Ele atualizará a imagem dentro do deployment da aplicação.
  • docker: container runtime
  • Kubernetes: um orquestrador de containers.

Pré requisitos

Criação do cluster

Nessa etapa criaremos nosso cluster k8s, instalaremos o argocd e por último criaremos a aplicação dentro do argo, onde ele vai monitorar as mudanças no repositório https://github.com/fabriciolfj/customer-service-k8s.
Com o clone do repositório customer-service efetuado, acesse o diretório cluster, nele existe o arquivo main.tf, onde encontra-se o descritivo do que o terraform criará. Dentro do main.tf, vamos olhar para o trecho abaixo e entender o que está ocorrendo.

resource "helm_release" "argocd" {
  name  = "argocd"

  repository       = "https://argoproj.github.io/argo-helm"
  chart            = "argo-cd"
  namespace        = "argocd"
  version          = "4.9.7"
  create_namespace = true

  values = [
    file("argocd/application.yaml")
  ]
}
Enter fullscreen mode Exit fullscreen mode

O trecho acima representa o uso de um módulo dentro do terraform. Onde ele executará as seguintes etapas:

  • instalar o argo dentro do cluster, com base na configuração do arquivo application.yaml
  • dentro deste arquivo encontra-se as configurações adicionais para criar aplicação dentro do argocd
  • quando falamos em criar aplicação dentro do argocd, é o repositório git com os manifestos que serão monitorados.
  • qualquer modificação nestes manifestos e submetidos ao repositório git, estes serão re-aplicados dentro do cluster kubernetes.

Abaixo o conteúdo do arquivo application.yaml e em seguida o arquivo que cria a app dentro do argocd (estão no repositório de exemplo salientado acima):

server:
  additionalApplications:
    - name: cluster-config
      namespace: argocd
      project: default
      source:
        repoURL: https://github.com/fabriciolfj/customer-service
        targetRevision: HEAD
        path: argocd/manifests/cluster #local onde encontra-se o arquivo para criar a app
        directory:
          recurse: true
      destination:
        server: https://kubernetes.default.svc
      syncPolicy:
        automated:
          prune: false
          selfHeal: false
Enter fullscreen mode Exit fullscreen mode
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: customer
  namespace: argocd
spec:
  syncPolicy:
    syncOptions:
      - CreateNamespace=false
    automated:
      selfHeal: true # sincronizar automaticamente com o repositorio
      prune: true # caso exclua algum arquivo, o argo vai excluir o recurso no kubernetes
  destination:
    server: 'https://kubernetes.default.svc'
    namespace: customer
  source:
    path: helm #por traz usaremos o helm para efetuar o deploy, dentro do cluster
    repoURL: 'https://github.com/fabriciolfj/customer-service-k8s' #repositório da app, que o argo aplicará no cluster quando houver commits.
    targetRevision: HEAD
    helm:
      valueFiles:
        - values.yaml
  project: default
Enter fullscreen mode Exit fullscreen mode

Os demais conteúdos do arquivo main.tf, tem por objetivo criar o cluster k8s local, utilizando kind. obs: está fora do escopo desse artigo o detalhamento desse conteúdos.
Certifique-se que o docker esteja rodando na sua máquina e execute o comando abaixo para inicializar o terraform, com as configurações do projeto, no path aonde encontra-se o arquivo main.tf:

terraform init
Enter fullscreen mode Exit fullscreen mode

Em seguida vamos analisar o que será criado, através do comando:

terraform plan
Enter fullscreen mode Exit fullscreen mode

Teremos o seguinte resultado:

  • Plan: 24 to add, 0 to change, 0 to destroy.

Após a criação do cluster, vamos acessar o argocd. Abaixo o script para pegar a senha admin:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo ``
Enter fullscreen mode Exit fullscreen mode

Para redirecionar a porta:

kubectl port-forward svc/argocd-server -n argocd 8080:80
Enter fullscreen mode Exit fullscreen mode

Acesse localhost:8080, usuário admin e a senha que você pegou conforme o script acima.

Image description

Github Actions

Para utilizar o CI/CD do githubactions, precisa constar um arquivo yaml no seguinte path do seu projeto: .github/workflows/commit-stage.yml
Abaixo a explicação de cada etapa que consta no nosso githubactions.

  • pipeline disparará a cada commit

name: Commit Stage
on: push
Enter fullscreen mode Exit fullscreen mode
  • variáveis de ambiente utilizados dentro desse contexto. obs: a tag version será alimentada pelo hash do commit.
env:
  REGISTRY: docker.io
  IMAGE_NAME: fabricio211/customer-service
  VERSION: ${{ github.sha }}
Enter fullscreen mode Exit fullscreen mode
  • job/build que primeiro fará o checkout do nosso código, usando como base uma imagem ubuntu
jobs:
  build:
    name: Build and Test
    runs-on: ubuntu-20.04
    permissions:
      contents: read
      security-events: write
    steps:
      - name: Checkout source code
        uses: actions/checkout@v2
Enter fullscreen mode Exit fullscreen mode
  • job/package executará os testes unitários, gerar a imagem docker com base nas variáveis de ambiente e por mim enviará ao registry do docker hub (obs: podemos utilizar o registry do próprio github).
  package:
    name: Package and Publish
    needs: [ build ]
    runs-on: ubuntu-20.04
    permissions:
      contents: read
      packages: write
      security-events: write
    steps:
      - name: Checkout source code
        uses: actions/checkout@v2
      - name: Set up JDK
        uses: actions/setup-java@v2
        with:
          distribution: temurin
          java-version: 17
          cache: maven
      - name: Build container image
        run: |
          chmod +x ./mvnw
          ./mvnw clean install spring-boot:build-image -Dspring-boot.build-image.imageName=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
      - name: Log into container registry
        uses: docker/login-action@v1
        with:
          registry: ${{ env.REGISTRY }}
          username: seu usuario 
          password: sua senha
      - name: Publish container image
        run: docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
      - name: Publish container image (latest)
        run: |
          docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
          docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
Enter fullscreen mode Exit fullscreen mode
  • por fim atualizaremos a imagem dentro do nosso manifesto, no outro repositório. obs: nesse ponto precisamos do secret do github para executar essa operação (salientado acima como proceder).
      - name: Update values.yaml
        uses: fjogeleit/yaml-update-action@v0.10.0
        with:
          valueFile: 'helm/values.yaml'
          propertyPath: 'image.tag'
          value: ${{ env.VERSION }}
          commitChange: true
          updateFile: true
          token: ${{ secrets.SPRING_FAST }}
          targetBranch: main
          branch: main
          repository: fabriciolfj/customer-service-k8s
Enter fullscreen mode Exit fullscreen mode

Ao realizar algum commit, você verá as seguintes situações.

  • entrega da app:
    Image description

  • commit no outro repositório

Image description

Aplicação

  • execute o script baixo que encontra-se no path raiz do projeto, dentro do namespace customer
kubectl apply -f postgresql.yaml
Enter fullscreen mode Exit fullscreen mode

Top comments (0)