
No Hub há muitos artigos sobre Jenkins, mas poucos descrevem um exemplo de funcionamento do Jenkins e dos agentes Docker. Todas as ferramentas de construção de projetos populares como , , , e outras, podem compilar tudo em contêineres. Mas e o Jenkins?
Atualmente, existe uma solução para este problema: o Jenkins 2 consegue trabalhar muito bem com . Neste artigo, quero compartilhar minha experiência e mostrar como você pode fazer isso também.
Por que eu decidi resolver esse problema?
Como nós, na empresa usamos muitas tecnologias diferentes, o servidor de construção precisa manter várias versões do Node.JS, Gradle, Ruby, JDK e outros. Mas muitas vezes, conflitos de versão são inevitáveis. Sim, você estaria certo se dissesse que existem diferentes gerenciadores de versão como nvm, rvm, mas nem tudo é tão simples com eles e essas soluções têm problemas:
- grande volume de runtimes que os desenvolvedores esquecem de limpar;
- existem conflitos entre diferentes versões de um mesmo runtime;
- cada desenvolvedor necessita de um conjunto diferente de componentes.
Existem outros problemas, mas melhor eu falar sobre a solução.
Jenkins no Docker
Dado que o Docker já está bem implantado na esfera de desenvolvimento, quase tudo pode ser executado com Docker. Minha solução é que o Jenkins esteja no Docker e possa executar outros contêineres Docker. Essa questão começou a ser debatida em 2013 em um artigo chamado “«.
Resumindo, é necessário instalar o próprio Docker no contêiner de trabalho e montar o arquivo /var/run/docker.sock.
Aqui está um exemplo de Dockerfile que eu criei para o Jenkins.
FROM jenkins/jenkins:lts
USER root
RUN apt-get update &&
apt-get -y install apt-transport-https
ca-certificates
curl
gnupg2
git
software-properties-common &&
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey &&
add-apt-repository
"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")
$(lsb_release -cs)
stable" &&
apt-get update &&
apt-get -y install docker-ce &&
usermod -aG docker jenkins
RUN curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose && chmod +x /usr/local/bin/docker-compose
RUN apt-get clean autoclean && apt-get autoremove --yes && rm -rf /var/lib/{apt,dpkg,cache,log}/
USER jenkinsAssim, obtivemos um contêiner Docker que pode executar comandos Docker na máquina hospedeira.
Configuração de Build
Recentemente, o Jenkins obteve a capacidade de descrever suas regras usando uma sintaxe que permite alterar facilmente o script de build e armazená-lo no repositório.
Vamos então colocar no próprio repositório um Dockerfile especial que conterá todas as bibliotecas necessárias para a construção. Dessa forma, o próprio desenvolvedor pode preparar um ambiente reproduzível e não será necessário pedir à equipe de OPS para instalar uma versão específica do Node.JS no host.
FROM node:12.10.0-alpine
RUN npm install yarn -gEsse template de construção é adequado para a maioria dos aplicativos Node.JS. E se você precisar de uma imagem para um projeto JVM com o scanner Sonar incluído? Você pode escolher os componentes necessários para a construção por conta própria.
FROM adoptopenjdk/openjdk12:latest
RUN apt update
&& apt install -y
bash unzip wget
RUN mkdir -p /usr/local/sonarscanner
&& cd /usr/local/sonarscanner
&& wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-3.3.0.1492-linux.zip
&& unzip sonar-scanner-cli-3.3.0.1492-linux.zip
&& mv sonar-scanner-3.3.0.1492-linux/* ./
&& rm sonar-scanner-cli-3.3.0.1492-linux.zip
&& rm -rf sonar-scanner-3.3.0.1492-linux
&& ln -s /usr/local/sonarscanner/bin/sonar-scanner /usr/local/bin/sonar-scanner
ENV PATH $PATH:/usr/local/sonarscanner/bin/
ENV SONAR_RUNNER_HOME /usr/local/sonarscanner/bin/
Descrevemos o ambiente de construção, mas qual é a relação com o Jenkins? Os agentes do Jenkins conseguem trabalhar com essas imagens Docker e realizar a construção internamente.
stage("Build project") {
agent {
docker {
image "project-build:${DOCKER_IMAGE_BRANCH}"
args "-v ${PWD}:/usr/src/app -w /usr/src/app"
reuseNode true
label "build-image"
}
}
steps {
sh "yarn"
sh "yarn build"
}
}Diretiva agente usa a propriedade docker, onde você pode especificar:
- o nome do container de construção de acordo com sua política de nomenclatura;
- os argumentos necessários para iniciar o container de construção, onde, no nosso caso, montamos o diretório atual como um diretório dentro do container.
E já nos passos de construção, indicamos quais comandos executar dentro do agente Docker de construção. Isso pode ser qualquer coisa, também uso assim para implantar aplicativos com o ansible.
Abaixo, quero mostrar um Jenkinsfile genérico que pode construir um simples aplicativo Node.JS.
def DOCKER_IMAGE_BRANCH = ""
def GIT_COMMIT_HASH = ""
pipeline {
options {
buildDiscarder(
logRotator(
artifactDaysToKeepStr: "",
artifactNumToKeepStr: "",
daysToKeepStr: "",
numToKeepStr: "10"
)
)
disableConcurrentBuilds()
}
agent any
stages {
stage("Prepare build image") {
steps {
sh "docker build -f Dockerfile.build . -t project-build:${DOCKER_IMAGE_BRANCH}"
}
}
stage("Build project") {
agent {
docker {
image "project-build:${DOCKER_IMAGE_BRANCH}"
args "-v ${PWD}:\/usr\/src\/app -w \/usr\/src\/app"
reuseNode true
label "build-image"
}
}
steps {
sh "yarn"
sh "yarn build"
}
}
post {
always {
step([$class: "WsCleanup"])
cleanWs()
}
}
}O que saiu disso?
Graças a esse método, resolvemos os seguintes problemas:
- o tempo de configuração do ambiente de build é reduzido para 10 a 15 minutos por projeto;
- um ambiente de build do aplicativo totalmente reproduzível, pois é possível compilar localmente também;
- não há problemas com conflitos entre diferentes versões das ferramentas de compilação;
- workspace sempre limpo, que não fica sobrecarregado.
A solução em si é simples e óbvia e permite obter apenas vantagens. Sim, a barreira de entrada aumentou um pouco em comparação com os comandos simples de build, mas agora há a garantia de que a construção será sempre feita, e o desenvolvedor pode escolher tudo o que é necessário para seu processo de compilação.
Você também pode utilizar a imagem que criei . Todos os códigos-fonte são abertos e estão disponíveis em .
Durante a redação do artigo, surgiu uma discussão sobre o uso de agentes em servidores remotos, para não sobrecarregar o nó mestre usando o plugin . Mas sobre isso falarei no futuro.
Fonte: habr.com
