Hoje em dia construir containers já faz parte do Dia a Dia de qualquer Sysadmin.

Após executar algumas vezes ninguém aguenta rodar mais docker build -t ., principalmente quando sua build tem varias dependências e fica atualizando a lista de pacotes o tempo todo, mesmo com o cache nos layers do docker as vezes fica muito demorado.

Para resolver esse problema normalmente utilizamos alguma ferramenta de Continuous Integration, ela será responsável por criar as imagens e enviar para algum repositório. Quando utilizamos o gitlab-ci nós podemos abstrair algumas partes do CI/CD, principalmente se utilizamos o registry do gitlab:

  • Configurar um web-hook para buildar quando enviamos o código
  • Criar credenciais para o push da imagem
  • Criar um webhook para nós avisar caso de falha
  • Configurar algum bot para criar um merge request quando a build for finalizada com sucesso
  • Criar webhooks para deploy no kubernetes

Para utilizar o Gitlab-CI, só precisamos de um Gitlab Runner configurado.

A versão gratuita do Gitlab já fornece a função de CI/CD sem precisar realizar nenhum configuração, é claro que iremos utilizar um recurso compartilhado, que pode ser utilizado por qualquer pessoa, o bom senso nos recomenda a não rodar nada confidencial lá.

Caso você não possua uma conta no Gitlab, é só acessar ele link e criar uma https://gitlab.com/users/sign_in. Com a versão gratuita do Gitlab nós temos acesso a repositórios públicos e privados com a função de CI/CD.


Nesse post vamos usar o repositório https://gitlab.com/odilonjunior/post-ci-cd como exemplo para o CI/CD, esse repo tem um codigo fonte java, que será construído via MVN depois seu artefato será copiado para um container que será responsável por executar o binário.

Nosso projeto possui essa estrutura.

├── Dockerfile
├── pom.xml
├── Readme.md
└── src
    └── main
        └── java
            └── Bootcamp.java

Nosso Dockerfile é bem simples, ele usa a estrutura de multistage, no primeiro estagio ele gera o binário, no segundo ele apenas adiciona para um container java e criar o nosso CMD.

FROM maven:alpine
WORKDIR /srv/
COPY src src
COPY pom.xml .
RUN mvn package

FROM openjdk:8-jdk-alpine 
WORKDIR /srv/
COPY --from=0 /srv/target/cicd-0.0.1.jar .
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar cicd-0.0.1.jar" ]

Para iniciar o CI/CD precisamos de um arquivo .gitlab-ci.yml na raiz do repositório, o nosso ficou construído da seguinte forma:

# This file is a template, and might need editing before it works on your project.
# Official docker image.
# Version 1.1
image: docker
services:
    - docker:dind

stages:
    - build

build_java:
    stage: build
    services:
        - docker:dind
    script:
        - docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY"
        - docker build -t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} .
        - docker tag ${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHA} ${CI_REGISTRY_IMAGE}:latest
        - docker push ${CI_REGISTRY_IMAGE}:latest
    tags:
        - docker

Nosso pipeline possui apenas um stage, que chamamos de build, e o build possui apenas um step, que é o build_java.

Ele vai executar em ordem, o login no registry do gitlab, utilizando as variáveis $CI_BUILD_TOKEN e $CI_REGISTRY como parâmetro, essas variáveis são globais no projeto, ela existem por padrão, toda vez que um pipeline é criado. Podemos verificar a lista de variáveis aqui https://docs.gitlab.com/ee/ci/variables/

Após executar o login nós vamos construir a imagem, utilizando as variáveis $CI_REGISTRY_IMAGE e $CI_COMMIT_SHA, a primeira variáveis vai ser o nome da imagem, como estamos usando o Gitlab publico ela ficara assim registry.gitlab.com/odilonjunior/post-ci-cd, a segunda variável faz referencia ao hash do commit, ele é aleatório, o hash vai servir como tag da nossa imagem.

O terceiro passo é um tag na imagem criada, vamos colocar a tag latest na imagem.

O ultimo passo é um docker push utilizando a variável CI_REGISTRY_IMAGE e a tag latest.

Você pode acompanhar o pipeline pela URL https://gitlab.com/odilonjunior/post-ci-cd/pipelines

Caso ele finalize com sucesso, o seguinte status vai aparecer:

Pipeline Status

E o log de saida do pipeline será parecido com esse:

Pipeline Log