Skip to main content

Harbor na Prática — Parte 7 Integração com GitLab CI

Nesta parte, vamos integrar o Harbor com o GitLab CI — configurando as variáveis de autenticação, buildando imagens dentro da pipeline e fazendo push automático para o Harbor a cada commit.


O fluxo que vamos construir

Developer faz push no GitLab


GitLab CI dispara


Build da imagem (Docker ou Kaniko)


Login no Harbor (Robot Account)


Push para harbor.empresa.com/projeto/app:branch-sha


Harbor escaneia com Trivy automaticamente

Pré-requisitos

  • Harbor instalado e acessível pelo GitLab Runner
  • Robot Account com permissão de push e pull no projeto (veja a Parte 3)
  • GitLab Runner configurado (Docker executor ou Kubernetes executor)

Passo 1 — Configurar as variáveis no GitLab

Nunca coloque credenciais diretamente no .gitlab-ci.yml. Use as variáveis de CI/CD do GitLab.

Acesse o projeto no GitLab → Settings → CI/CD → Variables → Add variable:

VariableValorMaskedProtected
HARBOR_REGISTRYharbor.empresa.com
HARBOR_PROJECTbackend
HARBOR_USERNAMErobot$backend+gitlab-ci
HARBOR_PASSWORDTOKEN_DO_ROBOT

Dica: Marque HARBOR_PASSWORD como Masked para que o valor não apareça nos logs da pipeline.


Passo 2 — Pipeline com Docker executor

Esta é a abordagem mais simples — o GitLab Runner usa Docker-in-Docker (dind) para buildar a imagem.

# .gitlab-ci.yml

stages:
- build
- push

variables:
IMAGE_NAME: $HARBOR_REGISTRY/$HARBOR_PROJECT/$CI_PROJECT_NAME
IMAGE_TAG: $CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA

build-and-push:
stage: build
image: docker:24
services:
- docker:24-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
# Se o Harbor usa HTTP (sem TLS)
DOCKER_OPTS: "--insecure-registry=harbor.empresa.com"
before_script:
- echo "$HARBOR_PASSWORD" | docker login $HARBOR_REGISTRY
-u "$HARBOR_USERNAME" --password-stdin
script:
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker push $IMAGE_NAME:$IMAGE_TAG
# Tag adicional com o nome do branch
- docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:$CI_COMMIT_REF_SLUG
- docker push $IMAGE_NAME:$CI_COMMIT_REF_SLUG
after_script:
- docker logout $HARBOR_REGISTRY
only:
- main
- develop
- /^feature\/.*$/

Passo 3 — Pipeline com Kaniko (recomendado para Kubernetes executor)

O Kaniko builda imagens sem precisar de Docker daemon — ideal quando o GitLab Runner está no Kubernetes.

# .gitlab-ci.yml

stages:
- build

variables:
IMAGE_NAME: $HARBOR_REGISTRY/$HARBOR_PROJECT/$CI_PROJECT_NAME
IMAGE_TAG: $CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA

build-kaniko:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.23.0-debug
entrypoint: [""]
script:
# Criar o arquivo de configuração do Docker com as credenciais do Harbor
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$HARBOR_REGISTRY\":{\"auth\":\"$(echo -n $HARBOR_USERNAME:$HARBOR_PASSWORD | base64)\"}}}" > /kaniko/.docker/config.json
# Build e push em um único comando
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $IMAGE_NAME:$IMAGE_TAG
--destination $IMAGE_NAME:$CI_COMMIT_REF_SLUG
--skip-tls-verify
only:
- main
- develop
- /^feature\/.*$/

O --skip-tls-verify é necessário apenas se o Harbor usa HTTP ou certificado autoassinado. Remova em produção com HTTPS válido.


Passo 4 — Pipeline completa com stages separados

Para pipelines mais organizadas, separando build, push e deploy:

# .gitlab-ci.yml

stages:
- build
- scan
- deploy

variables:
IMAGE_NAME: $HARBOR_REGISTRY/$HARBOR_PROJECT/$CI_PROJECT_NAME
IMAGE_TAG: $CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA

# --- BUILD ---
build:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.23.0-debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"$HARBOR_REGISTRY\":{\"auth\":\"$(echo -n $HARBOR_USERNAME:$HARBOR_PASSWORD | base64)\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $IMAGE_NAME:$IMAGE_TAG
--cache=true
--cache-repo=$HARBOR_REGISTRY/$HARBOR_PROJECT/cache
only:
- main
- develop
- merge_requests

# --- SCAN (aguardar Trivy no Harbor) ---
scan:
stage: scan
image: curlimages/curl:latest
script:
# Aguardar o scan automático do Harbor completar
- sleep 30
# Verificar resultado do scan — falha se houver vulnerabilidade CRITICAL
- |
RESULT=$(curl -s \
"https://$HARBOR_REGISTRY/api/v2.0/projects/$HARBOR_PROJECT/repositories/$CI_PROJECT_NAME/artifacts/$IMAGE_TAG/additions/vulnerabilities" \
-u "$HARBOR_USERNAME:$HARBOR_PASSWORD" | \
jq '.["application/vnd.security.vulnerability.report; version=1.1"].summary.summary.Critical // 0')
if [ "$RESULT" -gt "0" ]; then
echo "❌ Scan encontrou $RESULT vulnerabilidades CRITICAL. Deploy bloqueado."
exit 1
fi
echo "✅ Scan aprovado. Nenhuma vulnerabilidade CRITICAL."
only:
- main

# --- DEPLOY (atualizar manifests no GitLab para ArgoCD) ---
deploy:
stage: deploy
image: alpine/git:latest
script:
- echo "Nova imagem: $IMAGE_NAME:$IMAGE_TAG"
# Aqui você atualizaria os manifests Kubernetes ou o values.yaml do Helm
# para o ArgoCD detectar e fazer o deploy
only:
- main
when: on_success

Trabalhando com Harbor via HTTP (sem TLS)

Se o Harbor não usa HTTPS, é preciso configurar o Docker para aceitar o registry insecuro.

No GitLab Runner com Docker executor, adicione ao /etc/docker/daemon.json do host onde o runner roda:

{
"insecure-registries": ["harbor.empresa.com:32000"]
}

Para o Kaniko, use a flag --skip-tls-verify ou --insecure:

- /kaniko/executor
--context $CI_PROJECT_DIR
--dockerfile $CI_PROJECT_DIR/Dockerfile
--destination $IMAGE_NAME:$IMAGE_TAG
--skip-tls-verify # para HTTPS com cert autoassinado
--insecure # para HTTP puro

Estratégia de tagging recomendada

O GitLab disponibiliza variáveis predefinidas muito úteis para criar tags consistentes:

Variável GitLabExemplo de valorUso
$CI_COMMIT_REF_SLUGmain, feature-loginNome do branch formatado
$CI_COMMIT_SHORT_SHAa3f9c12Hash curto do commit
$CI_PIPELINE_ID12345ID único da pipeline
$CI_COMMIT_TAGv1.4.2Tag Git (quando existe)

Estratégia sugerida:

variables:
# Para branches normais: main-a3f9c12
IMAGE_TAG: $CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA

# Para tags Git (releases), usar a própria tag:
build-release:
script:
- /kaniko/executor
--destination $IMAGE_NAME:$CI_COMMIT_TAG
--destination $IMAGE_NAME:latest
only:
- tags

Verificando o resultado

Após a pipeline executar, verifique no Harbor:

Projects → backend → Repositories → nome-da-app

Você verá as tags criadas com o hash do commit, o scan de vulnerabilidades já executado e os detalhes de cada layer da imagem.

Via API:

curl -s "https://harbor.empresa.com/api/v2.0/projects/backend/repositories/minha-app/artifacts?page_size=5" \
-u "admin:suasenha" | \
jq '.[] | {tag: .tags[0].name, pushed: .push_time, scan: .scan_overview}'

Próximo artigo

Na Parte 8 — o artigo final da série — vamos configurar o Kubernetes para fazer pull de imagens privadas do Harbor usando imagePullSecrets e ServiceAccounts.