Categorias
DevOps

Gitlab 12.1 e Dind 19.03: Resolvendo problema com conexão TLS entre CI e Docker Registry

Até a versão 12, o Gitlab CI conectava ao docker registry próprio usando conexão não segura (sem TLS) por padrão.

Com a versão 19.03 do Dind (Docker-in-Docker), a conexão com o repositório passou a utilizar TLS por padrão. Do nada seus jobs começarão a falhar com alguma das mensagens abaixo:

Error response from daemon: Client sent an HTTP request to an HTTPS server.
<code>time="2019-08-06T19:24:46Z" level=error msg="failed to dial gRPC: cannot connect to the Docker daemon. Is 'docker daemon' running on this host?: dial tcp <some address>:2375: connect: connection refused"</code>
Cannot connect to the Docker daemon at tcp://docker:2375/. Is the docker daemon running?

Para resolver isso, podemos desabilitar explicitamente o TLS (o que não é recomendado e não entrarei em detalhes) ou configurar o nosso executor (runner) para utilizar TLS e é isso que faremos.

[[runners]]
  name = "nome-do-seu-runner"
  url = "https://<seu dominio do gitlab>"
  token = "<SEU TOKEN>"
  executor = "docker"
  environment = ["DOCKER_HOST=tcp://docker:2376", "DOCKER_DRIVER=overlay2", "DOCKER_TLS_VERIFY=1", "DOCKER_CERT_PATH=/certs/${CI_JOB_ID}/client", "DOCKER_TLS_CERTDIR=/certs/${CI_JOB_ID}"]
  [runners.docker]
    pull_policy = "if-not-present"
    privileged = true
    disable_cache = false
    volumes = ["/tmp/gitlab/docker/certs:/certs", "/cache"]

Explicando:

  • DOCKER_HOST=tcp://docker:2376 : define o host interno do daemon e a porta no qual está conectado. A porta não-TLS (antiga padrão) é 2375. É ela que precisa ser alterada para 2376.
  • DOCKER_TLS_VERIFY=1 : define que o daemon deve verificar o certificado utilizado na comunicação.
  • DOCKER_TLS_CERTDIR=/certs/${CI_JOB_ID} : aqui definimos onde o serviço do docker irá gerar seus certificados. É um absoluto interno do container. Utilizamos a variável ${CI_JOB_ID} para que não haja conflito com execuções paralelas.
  • DOCKER_CERT_PATH=/certs/${CI_JOB_ID}/client : define o caminho onde o serviço deve procurar o certificado de cliente para conexão TLS. É um subdiretório gerado pela configuração anterior.
  • volumes = [“/tmp/gitlab/docker/certs:/certs”, “/cache”] : definimos um diretório no nosso host (máquina que possui o gitlab-runner instalado) que será compartilhado com os containers em execução para armazenar os certificados gerados.

Outra configuração importante que deve ser removida (e por isso não consta no meu exemplo) é a tls_verify = false .

E é isso, agora só reiniciar seu runner por garantia – embora ele já atualize as configurações automaticamente: sudo systemctl restart gitlab-runner

Referências:

Categorias
DevOps

Como fiz o Gitlab gerar minhas imagens do Laradock

Já comentei diversas vezes que sou um usuário adito do Gitlab – como dizem por aí, desde quando tudo aquilo ali era mato. E um dos recursos que foram adicionados ao longo dos anos e eu mais utilizo é o de CI. Com ele consigo definir processos automáticos para testes, builds e deploy (esse, infelizmente, fora da minha realidade por enquanto) que são executados em containers ou máquinas especificamente designadas.

Se você olhar o repositório do Laradock, encontrará um arquivo com nome .gitlab-ci.yml. Esse arquivo é o responsável por dizer ao CI do Gitlab o que fazer quando uma alteração no repositório é enviada – ou quando o CI é disparado manualmente. Infelizmente ele não funcionará – a versão ali definida para o docker, dind e docker-compose estão defasadas, além disso, se você, como eu, utilizar o container registry do próprio Gitlab, essa informação deve ser adicionada ao arquivo.

O .gitlab-ci.yml atual do laradock começa desta forma:

# image: docker:latest
# services:
#   - docker:dind
image: jonaskello/docker-and-compose:1.12.1-1.8.0
services:
  - docker:1.12.1-dind

before_script:
  - docker info
  - docker-compose version
  - cp env-example .env
  - sed -i -- "s/=false/=true/g" .env
  - cat .env
  - env | sort

build:5.6:php-fpm:
  variables:
    PHP_VERSION: "5.6"
  script:
- docker-compose build php-fpm

Precisamos corrigir então:

  • Atualizar a imagem usada por: jonaskello/docker-and-compose:17.03.0-1.18.0
  • Atualizar a versão do service para: docker:18-dind
  • Incluir a variável DOCKER_HOST com valor tcp://docker:2375/
  • Incluir junto ao before_script a autenticação no seu registry para que seja possível fazer o push da imagem ao fim da geração. No meu caso, a linha fica: docker login -u gitlab-ci-token –password $CI_JOB_TOKEN registry.meudominio.com.br

Além disso, dentro do arquivo docker-compose.yml é preciso definir o caminho de cada imagem que você quer enviar ao container registry.

Por exemplo, no caso da imagem workspace as configurações devem ficar:

php-fpm:
      image: registry.meudominio.com.br/php-fpm:${PHP_VERSION}"
      build:
        context: ./php-fpm

Voltando ao .gitlab-ci.yml, em cada imagem que iremos construir devemos incluir o comando para fazer o push da imagem, todo o bloco de construção de uma imagem deve ficar parecido com o abaixo:

build:7.2:php-fpm:
  variables:
    PHP_VERSION: "7.2"
  script:
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker pull "registry.meudominio.com.br/php-fpm:${PHP_VERSION}" || true
    - docker-compose build php-fpm
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker-compose push php-fpm

Talvez você esteja perguntando por que tem duas chamadas ao docker login no processo de construção. A resposta é bem simples: garantir que não haja problema com sessão expirada. No meu setup, algumas imagens levam um bom tempo para serem construídas (culpa dos sistemas monolíticos) e no inicio eu tinha problema de ao tentar fazer o push da imagem, receber como resposta um Unauthorized.

Recapitulando, nosso .gitlab-ci.yml deve ficar parecido com:

image: jonaskello/docker-and-compose:17.03.0-1.18.0
services:
  - docker:18-dind

variables:
  DOCKER_HOST: tcp://docker:2375/
  DOCKER_DRIVER: overlay2

before_script:
  - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
  - docker info
  - docker-compose version
  - cp env-example .env
  - cat .env
  - env | sort

build:7.2:php-fpm:
  variables:
    PHP_VERSION: "7.2"
  script:
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker pull "registry.meudominio.com.br/php-fpm:${PHP_VERSION}" || true
    - docker-compose build php-fpm
    - docker login -u gitlab-ci-token --password $CI_JOB_TOKEN registry.meudominio.com.br
    - docker-compose push php-fpm

Último detalhe importante: o runner que vai executar esse build precisa ser do tipo Docker e deve ser executado em modo privilegiado (root), o que é não-recomendado em ambientes compartilhados – use uma máquina exclusivamente para CI, minimizando os riscos dessa configuração.
Agora você só precisa fazer o envio do seu código para instância do Gitlab que deseja usar e aguardar o build.

Se tiver alguma dica de como melhorar o setup, ou alguma dificuldade para fazer seu setup funcionar, deixe um comentário.