Jenkins - The Definitive Guide-Páginas-10

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 40

Machine Translated by Google

12.3. Implantando em um servidor de aplicativos

Jenkins fornece plug-ins para ajudá-lo a implantar seu aplicativo em vários servidores de aplicativos comumente usados. O
plugin Deploy permite implantar no Tomcat, JBoss e GlassFish. E o plugin Deploy Websphere tenta atender às particularidades
do IBM WebSphere Application Server.

Para outros servidores de aplicativos, normalmente você terá que integrar o processo de implantação em seus scripts de
construção ou recorrer a scripts personalizados para implantar seu aplicativo. Também para outras linguagens, seu processo de
implantação irá variar, mas muitas vezes envolverá algum uso de scripts de shell. Por exemplo, para uma aplicação Ruby on
Rails, você pode usar uma ferramenta como Capistrano ou Chef, ou simplesmente um shell script. Para uma aplicação PHP,
uma transferência de arquivos FTP ou SCP pode ser suficiente.

Vejamos primeiro algumas estratégias para implementar seus aplicativos Java em um servidor de aplicativos.

Isso é conhecido como hot-deploy, onde o aplicativo é implantado em um servidor em execução. Geralmente, essa é uma
maneira rápida e eficiente de colocar sua inscrição online. No entanto, dependendo do seu aplicativo e do seu servidor de
aplicativos, sabe-se que essa abordagem resulta em vazamentos de memória ou problemas de bloqueio de recursos – versões
mais antigas do Tomcat, por exemplo, eram particularmente conhecidas por isso. Se você se deparar com esse tipo de problema,
talvez seja necessário forçar a reinicialização do aplicativo após cada implantação ou possivelmente agendar uma reinicialização
noturna do servidor de aplicativos em sua máquina de teste.

12.3.1. Implantando um aplicativo Java


Nesta seção, veremos um exemplo de como implantar seu aplicativo Java web ou JEE em um servidor de aplicativos como
Tomcat, JBoss ou GlassFish.

Um dos princípios fundamentais da implantação automatizada é reutilizar seus binários. É ineficiente e potencialmente não
confiável reconstruir seu aplicativo durante o processo de implantação. Na verdade, imagine que você execute uma série de
testes de unidade e de integração em uma versão específica do seu aplicativo, antes de implantá-lo em um ambiente de teste
para testes adicionais. Se você reconstruir o binário antes de implementá-lo no ambiente de teste, o código-fonte poderá ter sido
alterado desde a revisão original, o que significa que você pode não saber exatamente o que está implementando.

Um processo mais eficiente é reutilizar os binários gerados por uma compilação anterior. Por exemplo, você pode configurar
uma tarefa de construção para executar testes de unidade e de integração antes de gerar um arquivo binário implementável
(normalmente um arquivo WAR ou EAR). Você pode fazer isso de forma muito eficaz usando o plugin Copy Artifact (veja Seção
10.7.2, “Copiando Artefatos”). Este plug-in permite copiar um artefato de outro espaço de trabalho de trabalho de construção
para o espaço de trabalho de trabalho de construção atual. Isso, quando combinado com um gatilho de construção normal ou
com o plug-in Build Promotion, permite implantar precisamente o arquivo binário que você construiu e testou na fase anterior.

Essa abordagem impõe algumas restrições à maneira como você cria seu aplicativo. Em particular, qualquer configuração
específica do ambiente deve ser externalizada para a aplicação; Conexões JDBC ou outros detalhes de configuração não devem
ser definidos em arquivos de configuração integrados em seu arquivo WAR, por exemplo, mas sim definidos usando JDNI ou
em um arquivo de propriedades externalizado. Se este não for o caso, você

330

www.dbooks.org
Machine Translated by Google

pode ser necessário compilar a partir de uma determinada revisão do SCM, conforme discutido para o Subversion na Seção 10.2.4, “Construindo

a partir de uma tag do Subversion”.

12.3.1.1. Usando o plug-in Deploy

Se você estiver implantando em um servidor Tomcat, JBoss ou GlassFish, a ferramenta mais útil à sua disposição
provavelmente será o plugin Deploy. Este plug-in torna relativamente simples integrar a implantação nessas plataformas
em seu processo de construção do Jenkins. Se você estiver implementando no IBM Websphere, poderá usar o plug-in
Websphere Deploy para fins semelhantes.

Vamos ver como esse plug-in funciona em ação, usando o pipeline simples de construção e implantação automatizada
ilustrado na Figura 12.1, “Um pipeline simples de implantação automatizada”.

Figura 12.1. Um pipeline de implantação automatizado simples

Aqui, a compilação padrão (gameoflife-default) executa os testes de unidade e integração e constrói um binário
implementável na forma de um arquivo WAR. A construção de métricas (gameoflife-metrics) executa verificações
adicionais em relação aos padrões de codificação e cobertura de código. Se ambas as compilações forem bem-
sucedidas, o aplicativo será implantado automaticamente no ambiente de teste pelo trabalho de compilação
gameoflife-deploy-to-test .

No trabalho de construção gameoflife-deploy-to-test, usamos o plugin Copy Artifact para recuperar o arquivo WAR
gerado no trabalho de construção gameoflife-default e copiá-lo para o espaço de trabalho do trabalho de construção
atual (veja a Figura 12.2, “Copiando o artefato binário a ser implantado”).

Figura 12.2. Copiando o artefato binário a ser implementado

331
Machine Translated by Google

A seguir, usamos o plugin Deploy para implantar o arquivo WAR no servidor de teste. É claro que geralmente é possível, e
não muito difícil, escrever um script de implantação feito manualmente para colocar seu aplicativo no servidor de aplicativos.
Em alguns casos, esta pode ser sua única opção. No entanto, se existir um plugin Jenkins para o seu servidor de aplicativos,
seu uso pode simplificar consideravelmente as coisas. Se você estiver implantando no Tomcat, JBoss ou GlassFish, o
plugin Deploy poderá funcionar para você. Este plugin usa Cargo para se conectar ao seu servidor de aplicativos e implantar
(ou reimplantar) seu aplicativo. Basta selecionar o tipo de servidor de destino e especificar a URL do servidor junto com o
nome de usuário e a senha de um usuário com direitos de implantação (consulte a Figura 12.3, “Implantando no Tomcat
usando o Deploy Plugin”).

Figura 12.3. Implantando no Tomcat usando o plug-in Deploy

Isso é conhecido como hot-deploy, onde o aplicativo é implantado em um servidor em execução. Geralmente, essa é uma
maneira rápida e eficiente de colocar seu aplicativo on-line e deve ser a solução preferida devido à sua conveniência em
termos de velocidade. No entanto, dependendo do seu aplicativo e do seu servidor de aplicativos, sabe-se que essa
abordagem resulta em vazamentos de memória ou problemas de bloqueio de recursos – versões mais antigas do Tomcat,
por exemplo, eram particularmente conhecidas por isso. Se você se deparar com esse tipo de problema, talvez seja
necessário forçar a reinicialização do aplicativo após cada implantação ou possivelmente agendar uma reinicialização
noturna do servidor de aplicativos em sua máquina de teste.

12.3.1.2. Reimplantando uma versão específica

Quando você implanta seu aplicativo de forma automática ou contínua, torna-se de importância crítica identificar com
precisão a versão do aplicativo atualmente implantada. Existem várias maneiras de fazer isso, que variam essencialmente
na função que Jenkins desempenha na arquitetura de construção/implantação.

Algumas equipes usam o Jenkins como o local central da verdade, onde os artefatos são construídos e armazenados para
referência futura. Se você armazena seus artefatos implantáveis no Jenkins, pode fazer todo o sentido implantar seus
artefatos diretamente de sua instância do Jenkins. Isso não é difícil de fazer: na próxima seção veremos como fazer isso
usando uma combinação dos plug-ins Copy Artifacts, Deploy e Parameterized Trigger.

Como alternativa, se você estiver usando um repositório corporativo, como Nexus ou Artifactory, para armazenar seus
artefatos, esse repositório deverá atuar como o ponto central de referência: Jenkins deverá criar e implantar artefatos em
seu repositório central e, em seguida, implantá-los a partir daí. Normalmente, esse é o caso se você estiver usando o
Maven como ferramenta de construção, mas equipes que usam ferramentas como Gradle ou Ivy também podem usar essa abordagem.
Gerenciadores de repositórios como Nexus e Artifactory, especialmente em suas edições comerciais, facilitam a
implementação dessa estratégia, fornecendo recursos como promoção de build e repositórios de teste que ajudam a
gerenciar o estado de lançamento de seus artefatos.

Vejamos como você pode implementar cada uma dessas estratégias usando Jenkins.

332

www.dbooks.org
Machine Translated by Google

12.3.1.3. Implantando uma versão de uma versão anterior do Jenkins

Reimplantar um artefato previamente implantado no Jenkins é relativamente simples. Na Seção 12.3.1.1, “Usando o plugin Deploy”,
vimos como usar os plugins Copy Artifacts e Deploy para implementar um arquivo WAR construído por uma tarefa de construção
anterior em um servidor de aplicativos. O que precisamos fazer agora é permitir que o usuário especifique a versão a ser
implantada, em vez de apenas implantar a versão mais recente.

Podemos fazer isso usando o plugin Parameterized Trigger (veja Seção 10.2, “Trabalhos de construção parametrizados”).
Primeiro, adicionamos um parâmetro ao trabalho de construção, usando o tipo de parâmetro especial “Build selector for Copy
Artifact” (veja Figura 12.4, “Adicionando um parâmetro “Build selector for Copy Artifact””).

Figura 12.4. Adicionando um parâmetro “Seletor de construção para artefato de cópia”

Isso adiciona um novo parâmetro ao seu build job (veja Figura 12.5, “Configurando um parâmetro do seletor de build”).
Aqui você precisa inserir um nome e uma breve descrição. O nome fornecido será usado como uma variável de ambiente passada
para as etapas de construção subsequentes.

Figura 12.5. Configurando um parâmetro do seletor de build

O tipo de parâmetro do seletor de build permite escolher um build anterior de diversas maneiras, incluindo o build bem-sucedido
mais recente, o build upstream que acionou esse trabalho de build ou um build específico. Todas essas opções estarão disponíveis
para o usuário quando ele acionar uma compilação. O Seletor Padrão permite especificar quais destas opções serão propostas
por padrão.

333
Machine Translated by Google

Quando o usuário seleciona um trabalho de construção específico, o número da construção também será armazenado nas variáveis de
ambiente para uso nas etapas de construção. A variável de ambiente é chamada COPYARTIFACT_BUILD_NUMBER_MY_BUILD_JOB,
onde MY_BUILD_JOB é o nome do trabalho de construção original (em letras maiúsculas e com caracteres diferentes de A–Z convertidos
em sublinhados). Por exemplo, se copiarmos um artefato da compilação número 4 do projeto gameoflife-default, a variável de ambiente
COPYARTIFACT_BUILD_NUMBER_GAMEOFLIFE_DEFAULT seria definida como 4.

A segunda parte da configuração é dizer ao Jenkins o que buscar e de qual trabalho de construção. Na seção Build da configuração do
nosso projeto, adicionamos uma etapa “Copiar artefatos de outro projeto”. Aqui você especifica o projeto onde o artefato foi construído e
arquivado (gameoflife-default em nosso exemplo).
Você também precisa fazer com que o Jenkins use a construção especificada no parâmetro que definimos anteriormente. Você faz isso
escolhendo “Especificado por um parâmetro de compilação” na opção “Qual compilação” e fornecendo o nome da variável que
especificamos anteriormente no campo de nome do seletor de compilação (consulte a Figura 12.6, “Especifique onde encontrar os
artefatos a serem implementados” ). Depois, basta configurar os artefatos para copiar como fizemos no exemplo anterior.

Figura 12.6. Especifique onde encontrar os artefatos a serem implantados

Finalmente, implantamos o artefato copiado usando o plugin Deploy, conforme ilustrado na Figura 12.3, “Implantando no Tomcat usando
o plugin Deploy”.

Então vamos ver como essa build funciona na prática. Quando iniciamos uma compilação manualmente, Jenkins irá propor uma lista de
opções permitindo que você selecione a compilação a ser reimplantada (veja a Figura 12.7, “Escolhendo a compilação a ser reimplantada”).

Figura 12.7. Escolhendo a compilação para reimplantar

334

www.dbooks.org
Machine Translated by Google

A maioria dessas opções é bastante autoexplicativa.

A “última versão bem-sucedida” é a versão mais recente, excluindo quaisquer versões com falha. Portanto, esta opção normalmente irá

apenas reimplantar a versão mais recente novamente. Se você usar esta opção, provavelmente desejará marcar a caixa de seleção “Somente

compilações estáveis”, o que também excluirá quaisquer compilações instáveis.

Se você optou por descartar compilações antigas, você poderá sinalizar certos trabalhos de construção para serem mantidos para sempre

(veja Seção 5.3.1, “Opções Gerais”). Nesse caso, você pode optar por implantar a “última compilação salva”.

Uma opção sensata para um trabalho de construção automatizado no final de um pipeline de construção é “Compilação upstream que acionou

este trabalho”. Dessa forma, você pode ter certeza de que está implantando o artefato que foi gerado (ou promovido por meio) do trabalho de

build anterior, mesmo que outros builds tenham ocorrido desde então. Vale a pena notar que, embora esse tipo de trabalho de construção

parametrizado seja frequentemente usado para implantar manualmente um artefato específico, ele também pode ser usado efetivamente

como parte de um processo de construção automatizado. Se não for acionado manualmente, ele simplesmente usará qualquer valor que você

definir no campo “seletor padrão”.

Você também pode escolher a opção “Especificado por link permanente” (veja Figura 12.8, “Usando a opção “Especificado por link

permanente”). Isso permite escolher entre vários valores de atalho, como a última compilação, a última compilação estável, a última compilação
bem-sucedida e assim por diante.

Figura 12.8. Usando a opção “Especificado por link permanente”

Entretanto, se você quiser reimplantar uma versão específica da sua aplicação, uma opção mais útil é “Compilação específica” (veja Figura

12.9, “Usando uma compilação específica”). Esta opção permite fornecer um número de build específico a ser implantado. Essa é a maneira

mais flexível de reimplantar um aplicativo — você só precisará saber o número do build que precisa reimplantar, mas isso geralmente não é

muito difícil de encontrar observando o histórico de build do trabalho de build original.

Figura 12.9. Usando uma compilação específica

335
Machine Translated by Google

Esta é uma maneira conveniente de implantar ou reimplantar artefatos de trabalhos de construção anteriores do Jenkins. No
entanto, em alguns casos você pode preferir usar um artefato armazenado em um repositório corporativo como Nexus ou Artifactory.
Veremos um exemplo de como fazer isso na próxima seção.

12.3.1.4. Implantando uma versão de um repositório Maven

Muitas organizações usam um gerenciador de repositório corporativo, como Nexus e Artifactory, para armazenar e compartilhar
artefatos binários, como arquivos JAR. Essa estratégia é comumente usada com Maven, mas também com outras ferramentas
de construção, como Ant (com Ivy ou Maven Ant Tasks) e Gradle. Usando essa abordagem em um ambiente de CI, tanto as
dependências de snapshot quanto de release são construídas em seu servidor Jenkins e, em seguida, implantadas em seu
gerenciador de repositório (consulte a Figura 12.10, “Usando um repositório Maven Enterprise”).
Sempre que um desenvolvedor envia alterações no código-fonte para o sistema de controle de versão, Jenkins capta as
alterações e cria novas versões instantâneas dos artefatos correspondentes. Jenkins então implanta esses artefatos de snapshot
no Enterprise Repository Manager local, onde eles podem ser disponibilizados para outros desenvolvedores da equipe ou de
outras equipes da organização. Discutimos como fazer com que o Jenkins implante automaticamente artefatos Maven em um
repositório corporativo na Figura 12.10, “Usando um repositório corporativo Maven”. Uma abordagem semelhante também pode
ser feita usando Gradle ou Ivy.

Implantações
Atualizações de
de instantâneo
instantâneos
Repositório corporativo Maven

Construção de CI

Desenvolvedores
servidor

Mudanças

no código-fonte
Automatizado

atualizações e compilações

Servidor SCM

Figura 12.10. Usando um repositório Maven Enterprise

As convenções do Maven usam um sistema bem definido de números de versão, distinguindo entre as versões SNAPSHOT e
RELEASE. As versões SNAPSHOT são consideradas compilações potencialmente instáveis da base de código mais recente,
enquanto as versões RELEASE são lançamentos oficiais que passaram por um processo de lançamento mais formal.
Normalmente, os artefatos SNAPSHOT são reservados para uso dentro de uma equipe de desenvolvimento, enquanto as
versões RELEASE são consideradas prontas para testes adicionais.

336

www.dbooks.org
Machine Translated by Google

Uma abordagem semelhante pode ser usada para artefatos implementáveis, como arquivos WAR ou EAR — eles são
construídos e testados no servidor de CI e, em seguida, implementados automaticamente no Enterprise Repository, muitas
vezes como parte de um pipeline de construção envolvendo testes automatizados e verificações de qualidade (consulte a Seção
10.7, “Construir Pipelines e Promoções”). As versões SNAPSHOT são normalmente implantadas em um servidor de teste para
testes automatizados e/ou manuais, a fim de decidir se uma versão está pronta para ser lançada oficialmente.

A estratégia exata usada para decidir quando uma versão de lançamento será criada e como ela será implantada varia muito
de uma organização. Por exemplo, algumas equipes preferem um lançamento formal no final de cada iteração ou sprint, com
um número de versão bem definido e um conjunto correspondente de notas de lançamento que são distribuídas às equipes de
controle de qualidade para testes adicionais. Quando uma versão específica recebe aprovação do controle de qualidade, ela
pode ser implantada na produção. Outros, usando uma abordagem mais enxuta, preferem lançar uma nova versão sempre que
um novo recurso ou correção de bug estiver pronto para ser implantado. Se uma equipe estiver particularmente confiante em
seus testes automatizados e verificações de qualidade de código, pode até ser possível automatizar completamente esse
processo, gerando e lançando uma nova versão periodicamente (digamos, todas as noites) ou sempre que novas alterações
forem confirmadas.

Existem muitas maneiras de implementar esse tipo de estratégia. No restante desta seção, veremos como fazer isso usando
um projeto Maven multimódulo convencional. Nosso projeto de exemplo é uma aplicação web chamada gameoflife, que
consiste em três módulos: gameoflife-core, gameoflife-services e gameoflife-web. O módulo gameoflife-web produz um
arquivo WAR que inclui arquivos JAR dos outros dois módulos. É este arquivo WAR que queremos implantar:

tuatara:gameoflife johnsmart$ ls -l total 32

drwxr-xr-x 16 johnsmart staff 544 16 de maio 09:58 gameoflife-core drwxr-xr-x 8 johnsmart staff 272 4 de
maio 18:12 gameoflife-deploy drwxr-xr-x 8 johnsmart staff 272 16 de maio 09:58 gameoflife- serviços drwxr-xr-x
15 equipe johnsmart 510 16 de maio 09:58 gameoflife-web -rw-r--r--@ 1 equipe johnsmart 12182 4 de maio 18:07
pom.xml

Anteriormente neste capítulo, vimos como usar o plug-in Deploy para implementar um arquivo WAR gerado pela tarefa de
construção atual em um servidor de aplicativos. O que queremos fazer agora é implementar uma versão arbitrária do arquivo
WAR em um servidor de aplicativos.

Na Seção 10.7.1, “Gerenciando versões do Maven com o plug-in M2Release”, discutimos como configurar o Jenkins para
invocar o plug-in de liberação do Maven para gerar uma versão de lançamento formal de um aplicativo. A primeira etapa do
processo de implantação começa aqui, então assumiremos que isso foi configurado e que algumas versões já foram
implementadas em nosso Enterprise Repository Manager.

A próxima etapa envolve a criação de um projeto dedicado para gerenciar o processo de implantação. Este projeto será um
projeto Maven padrão.

A primeira coisa que você precisa fazer é configurar um projeto de implantação dedicado. Em sua forma mais simples, este
projeto simplesmente buscará a versão solicitada do seu arquivo WAR do repositório corporativo para ser implantada pelo
Jenkins. No arquivo pom.xml a seguir , usamos o maven-war-plugin para buscar uma versão especificada do arquivo WAR
gameoflife-web de nosso repositório corporativo. A versão que queremos é especificada na propriedade target.version :

337
Machine Translated by Google

<projeto xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/


Instância XMLSchema"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-
v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wakaleo.gameoflife</groupId>
<artifactId>gameoflife-deploy-with-jenkins</artifactId> <version>0.0.1-SNAPSHOT</
version> <packaging>war</packaging>
<dependencies> < dependência>

<groupId>com.wakaleo.gameoflife</groupId> <artifactId>gameoflife-
web</artifactId> <type>war</type>d <version>${target.version}
</version>

</dependency> </
dependencies>
<construir>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId> <configuration>

<warName>gameoflife</warName>
<overlays>
<overlay>
<groupId>com.wakaleo.gameoflife</groupId>
<artifactId>gameoflife-web</artifactId> </overlay> </
overlays> </
configuration> </
plugin> </plugins> </
build>

<properties>
<target.version>RELEASE</target.version>
</propriedades> </
projeto>

A seguir, configuramos um trabalho de construção do Jenkins para invocar esse arquivo pom.xml usando um valor de
propriedade fornecido pelo usuário (consulte a Figura 12.11, “Implantando um artefato de um repositório Maven”). Observe
que definimos o valor padrão como RELEASE para que, por padrão, a versão de lançamento mais recente seja implantada.
Caso contrário, o usuário poderá fornecer o número da versão a ser implantada ou reimplantada.

338

www.dbooks.org
Machine Translated by Google

Figura 12.11. Implantando um artefato de um repositório Maven

O restante deste trabalho de construção simplesmente verifica o projeto de implantação e invoca o objetivo do pacote mvn
e, em seguida, implanta o arquivo WAR usando o plug-in Deploy (consulte a Figura 12.12, “Preparando o WAR para ser
implantado”). A propriedade target.version será automaticamente passada para o trabalho de construção e usada para
implantar a versão correta.

Figura 12.12. Preparando a GUERRA para ser implantada

Técnicas semelhantes podem ser usadas para outros tipos de projetos. Se estiver implantando em um servidor de aplicativos
que não é suportado pelo plug-in Deploy, você também terá a opção de escrever um script personalizado em qualquer idioma
que seja mais conveniente e fazer com que Jenkins passe o número da versão solicitada como parâmetro, conforme descrito
acima.

12.3.2. Implantando aplicativos baseados em scripts, como Ruby e PHP


A implantação de projetos usando linguagens de script como PHP e Ruby é geralmente mais simples do que a implantação
de aplicativos Java, embora os problemas relacionados às atualizações do banco de dados sejam semelhantes. Na verdade,
muitas vezes essas implantações envolvem essencialmente a cópia de arquivos para um servidor remoto. Para obter os
arquivos em primeiro lugar, você tem a opção de copiá-los do espaço de trabalho de outro trabalho de construção usando a
opção Copiar Artefatos ou fazer check-out do código-fonte diretamente do repositório de código-fonte, se necessário, usando um

339
Machine Translated by Google

revisão ou tag específica conforme descrito para o Subversion na Seção 10.2.4, “Construindo a partir de uma Tag
do Subversion” e para o Git na Seção 10.2.5, “Construindo a partir de uma Tag do Git”. Então, depois de ter o código-
fonte em seu espaço de trabalho Jenkins, basta implantá-lo no servidor de destino.

Uma ferramenta útil para esse tipo de implantação é a série de plug-ins Publish Over para Jenkins (Publish Over
FTP, Publish Over SSH e Publish Over CIFS). Esses plug-ins fornecem uma maneira consistente e flexível de
implantar artefatos de seu aplicativo em outros servidores por meio de vários protocolos, incluindo CIFS (para
unidades compartilhadas do Windows), FTP e SSH/SFTP.

A configuração de cada um desses plugins é semelhante. Depois de instalar os plug-ins, você precisa definir as
configurações do host, que são gerenciadas centralmente na tela de configuração principal. Você pode criar quantas
configurações de host desejar – elas aparecerão em uma lista suspensa na página de configuração do trabalho.

A configuração dos hosts é bastante autoexplicativa (veja Figura 12.13, “Configurando um host remoto”).
O nome é o nome que aparecerá na lista suspensa nas configurações do trabalho de construção. Você pode
configurar a autenticação usando um nome de usuário e senha para FTP, ou uma chave SSH ou um nome de
usuário e senha para SSH. Você também precisa fornecer um diretório existente no servidor remoto que atuará no
diretório raiz para esta configuração. Nas opções avançadas, você também pode configurar a porta SSH e as opções
de tempo limite.

Figura 12.13. Configurando um host remoto

340

www.dbooks.org
Machine Translated by Google

Depois de configurar seus hosts, você poderá configurar seus trabalhos de construção para implementar artefatos nesses hosts.
Você pode fazer isso como uma etapa de construção (veja a Figura 12.14, “Implantando arquivos em um host remoto na seção de
construção”) ou como uma ação pós-construção (veja a Figura 12.15, “Implantando arquivos em um host remoto na seção de construção).
construir ações”). Em ambos os casos, as opções são semelhantes.

Figura 12.14. Implantando arquivos em um host remoto na seção de construção

Primeiro de tudo, você seleciona o host de destino na lista de hosts configurados na seção anterior. A seguir, você configura os arquivos
que deseja transferir. Você faz isso definindo um ou mais “conjuntos de transferência”. Um conjunto de transferência é um conjunto de
arquivos (definido por uma expressão de conjunto de arquivos Ant) que você implementa em um diretório especificado no servidor remoto.
Você também pode fornecer um prefixo a ser removido - isso permite remover diretórios desnecessários que você não deseja que
apareçam no servidor (como o caminho do diretório de destino/site no exemplo). Você pode adicionar quantos conjuntos de transferência
forem necessários para colocar os arquivos desejados no servidor remoto. O plugin também oferece opções para executar comandos no
servidor remoto assim que a transferência for concluída (“comando Exec”) ou para excluir determinados arquivos ou nivelar os diretórios.

341
Machine Translated by Google

Figura 12.15. Implantando arquivos em um host remoto nas ações pós-compilação

12.4. Conclusão
A Implantação Automatizada, e em sua forma mais avançada, a Implantação Contínua ou Entrega Contínua, pode ser
considerada o ponto culminante de uma infraestrutura moderna de Integração Contínua.

Neste capítulo, revisamos diversas técnicas de implantação automatizada, principalmente centradas em implantações
baseadas em Java. No entanto, os princípios gerais discutidos aqui aplicam-se a qualquer tecnologia.
Na verdade, o processo real de implantação em muitas outras tecnologias, em particular linguagens de script como
Ruby e PHP, é consideravelmente mais simples do que quando se utiliza Java e envolve essencialmente a cópia de
arquivos para o servidor de produção. Ruby também se beneficia de ferramentas como Heroku e Capistrano para
facilitar a tarefa.

Há vários aspectos importantes que você precisa considerar ao configurar uma implantação automatizada.
Em primeiro lugar, a implantação automatizada é o ponto final de sua arquitetura de CI: você precisa definir um pipeline
de construção para levar sua construção desde a compilação inicial e testes unitários, até testes de aceitação funcionais
e automatizados mais abrangentes e verificações de qualidade de código, culminando em implantação em uma ou
mais plataformas. O grau de confiança que você pode ter em seu pipeline de construção depende muito do grau de
confiança que você tem em seus testes. Ou, em outros termos, quanto menos confiáveis e abrangentes forem seus
testes, mais cedo no processo de construção você terá que recorrer a testes manuais e à intervenção humana.

342

www.dbooks.org
Machine Translated by Google

Finalmente, se possível, é importante construir seu artefato implementável uma vez e apenas uma vez e, em seguida,
reutilizá-lo nas etapas subsequentes para testes funcionais e implantação em diferentes plataformas.

343
Machine Translated by Google

www.dbooks.org
Machine Translated by Google

Capítulo 13. Mantendo Jenkins


13.1. Introdução

Neste capítulo, discutiremos algumas dicas e truques que podem ser úteis ao manter uma grande instância do Jenkins. Veremos coisas
como limitar e controlar o uso do disco, como fornecer memória suficiente ao Jenkins e como arquivar trabalhos de construção ou migrá-
los de um servidor para outro.
Alguns desses tópicos são discutidos em outras partes do livro, mas aqui veremos as coisas do ponto de vista do administrador do
sistema.

13.2. Monitorando o espaço em disco

O histórico de compilação ocupa espaço em disco. Além disso, Jenkins analisa os registros de construção quando carrega uma
configuração de projeto, portanto, um trabalho de construção com mil compilações arquivadas levará muito mais tempo para carregar do
que um com apenas cinquenta. Se você tiver um grande servidor Jenkins com dezenas ou centenas de trabalhos de construção,
multiplique isso de acordo.

Provavelmente, a maneira mais simples de manter um limite no uso do disco é limitar o número de compilações que um projeto mantém
em seu histórico. Você pode configurar isso marcando a caixa de seleção Discard Old Builds no topo da página de configuração do
projeto (veja Figura 13.1, “Descartando compilações antigas”). Se você disser ao Jenkins para manter apenas as últimas 20 compilações,
ele começará a descartar (e excluir) trabalhos de compilação mais antigos quando atingir esse número. Você pode limitá-los por número
(ou seja, não mais que 20 compilações) ou por data (ou seja, compilações com no máximo 30 dias). Porém, ele faz isso de maneira
inteligente: se alguma vez houve uma compilação bem-sucedida, o Jenkins sempre manterá pelo menos a última compilação bem-
sucedida como parte de seu histórico de compilação, para que você nunca perca sua última compilação bem-sucedida.

Figura 13.1. Descartando construções antigas

O problema de descartar compilações antigas é que você perde o histórico de compilações ao mesmo tempo. Jenkins usa os registros
de construção para produzir gráficos de resultados de testes e métricas de construção. Se você limitar o número de compilações a
Machine Translated by Google

ser mantido em vinte, por exemplo, o Jenkins exibirá apenas gráficos contendo os últimos vinte pontos de dados, o que pode ser
um pouco limitado. Esse tipo de informação pode ser muito útil para os desenvolvedores, mas muitas vezes é bom poder ver
como estão as métricas do projeto ao longo de toda a vida do projeto, não apenas nas últimas duas semanas.

Felizmente, Jenkins tem uma solução alternativa que pode manter os desenvolvedores e administradores de sistema satisfeitos.
Em geral, os itens que ocupam mais espaço em disco são os artefatos de construção: arquivos JAR, arquivos WAR e assim por
diante. O histórico de construção em si é composto principalmente de arquivos de log XML, que não ocupam muito espaço. Se
você clicar no botão “Avançado...” o Jenkins permitirá descartar os artefatos, mas não os dados de construção. Na Figura 13.2,
“Descartando compilações antigas – opções avançadas”, por exemplo, configuramos o Jenkins para manter artefatos por no
máximo 7 dias. Essa é uma ótima opção se você precisar limitar o uso do disco, mas ainda quiser fornecer um escopo completo
de métricas de construção para as equipes de desenvolvimento.

Figura 13.2. Descartando versões antigas – opções avançadas

Não hesite em ser implacável, mantendo o número máximo de construções com artefatos bastante baixo.
Lembre-se, Jenkins sempre manterá as últimas construções estáveis e as últimas compilações bem-sucedidas, não importa o
que você diga, então você sempre terá pelo menos um artefato funcional (a menos, é claro, que o projeto ainda não tenha sido
compilado com sucesso). Jenkins também permite marcar uma compilação individual como “Manter este log para sempre”, para
evitar que certas compilações importantes sejam descartadas automaticamente.

13.2.1. Usando o plug-in de uso de disco

Uma das ferramentas mais úteis na caixa de ferramentas do administrador Jenkins é o plugin Disk Usage. Este plugin registra e
relata a quantidade de espaço em disco usado por seus projetos. Ele permite isolar e corrigir projetos que usam muito espaço
em disco.

Você pode instalar o plugin Disk Usage da maneira usual, na tela do Plugin Manager. Depois de instalar o plugin e reiniciar o
Jenkins, o plugin Disk Usage registrará a quantidade de espaço em disco usado por cada projeto. Ele também adicionará um link
Disk Usage na tela Manage Jenkins, que você pode usar para exibir o uso geral do disco para seus projetos (veja a Figura 13.3,
“Visualizando o uso do disco”).

346

www.dbooks.org
Machine Translated by Google

Figura 13.3. Visualizando o uso do disco

Esta lista é classificada pelo uso geral do disco, portanto, os projetos que usam mais espaço em disco ficam no topo. A lista
fornece dois valores para cada projeto: a coluna Builds indica a quantidade total de espaço usado por todo o histórico de build
do projeto, enquanto a coluna Workspace indica a quantidade de espaço usado para construir o projeto. Para projetos em
andamento, o valor do espaço de trabalho tende a ser relativamente estável (um projeto precisa do que precisa para ser
construído corretamente), enquanto a coluna Builds aumentará com o tempo, às vezes em um ritmo dramático, a menos que
você faça algo a respeito. Você pode manter o espaço necessário para o histórico de um projeto sob controle limitando o
número de compilações mantidas para um projeto e tomando cuidado com quais artefatos estão sendo armazenados.

Para ter uma ideia da rapidez com que o espaço em disco está sendo consumido, você também pode exibir a quantidade de
espaço em disco usado em cada projeto ao longo do tempo. Para fazer isso, você precisa ativar o plugin na tela Configuração
do Sistema (veja Figura 13.4, “Exibindo o uso do disco para um projeto”).

Figura 13.4. Exibindo o uso do disco para um projeto

Isso registrará e exibirá quanto espaço seus projetos estão usando ao longo do tempo. O plugin Disk Usage exibe um gráfico
do uso do disco ao longo do tempo (veja a Figura 13.5, “Exibindo o uso do disco do projeto ao longo do tempo”), o que pode
lhe dar uma excelente visão de quão rápido seu projeto está enchendo o disco, ou, pelo contrário , se o uso do disco permanecer
estável ao longo do tempo.

347
Machine Translated by Google

Figura 13.5. Exibindo o uso do disco do projeto ao longo do tempo

13.2.2. Uso de disco e tipo de projeto Jenkins Maven


Se você estiver usando os trabalhos de construção do Jenkins Maven, há alguns detalhes adicionais que você deve conhecer.
No Jenkins, os trabalhos de construção do Maven arquivarão automaticamente seus artefatos de construção por padrão. Isso pode
não ser o que você pretende.

O problema é que esses artefatos SNAPSHOT ocupam muito espaço. Em um projeto ativo, o Jenkins pode executar vários builds por
hora, portanto, armazenar permanentemente os arquivos JAR gerados para cada build pode ser muito caro. O problema se acentua se
você tiver projetos multimódulos, pois o Jenkins arquivará os artefatos gerados para cada módulo.

Na verdade, se você precisar arquivar seus artefatos Maven SNAPSHOT, provavelmente é melhor implantá-los diretamente em seu
gerenciador de repositório Maven local. O Nexus Pro, por exemplo, pode ser configurado para fazer isso e o Artifactory pode ser
configurado para excluir artefatos de instantâneos antigos.

Felizmente, você pode configurar o Jenkins para isso, vá para a seção “Build” da tela de configuração do seu trabalho de construção e
clique no botão Avançado. Isso exibirá alguns campos extras, como mostrado na Figura 13.6, “Trabalhos de construção do Maven –
opções avançadas”.

Figura 13.6. Jobs de construção do Maven – opções avançadas

348

www.dbooks.org
Machine Translated by Google

Se você marcar a caixa de seleção “Desativar arquivamento automático de artefatos” aqui, Jenkins evitará armazenar os arquivos jar
gerados pela construção do seu projeto. Esta é uma boa maneira de deixar feliz o seu amigável administrador de sistema.

Observe que às vezes você precisa armazenar os artefatos do Maven. Por exemplo, eles geralmente são úteis ao implementar um
pipeline de construção (consulte a Seção 10.7, “Construir pipelines e promoções”). Nesse caso, você sempre pode optar por arquivar
manualmente os artefatos necessários e, em seguida, usar a opção “Descartar compilações antigas” para refinar por quanto tempo
você os manterá.

13.3. Monitorando a carga do servidor

Jenkins fornece monitoramento integrado da atividade do servidor. Na tela Gerenciar Jenkins, clique no ícone Carregar estatísticas.
Isso exibirá um gráfico da carga do servidor ao longo do tempo para o nó mestre (consulte a Figura 13.7, “Estatísticas de carga do
Jenkins”). Este gráfico acompanha três métricas: o número total de executores, o número de executores ocupados e o comprimento
da fila.

O número total de executores (a linha azul) inclui os executores nos nós mestre e escravo. Isso pode variar quando os escravos
são ativados e off-line e pode ser um indicador útil de quão bem o provisionamento dinâmico de nós escravos está funcionando.

O número de executores ocupados (a linha vermelha) indica quantos de seus executores estão ocupados executando compilações.
Você deve certificar-se de ter capacidade ociosa suficiente aqui para absorver picos em trabalhos de construção. Se todos os seus
executores estiverem permanentemente ocupados executando trabalhos de construção, você deverá adicionar mais executores e/ou
nós escravos.

O comprimento da fila (a linha cinza) é o número de trabalhos de construção aguardando execução. Os trabalhos de construção
são enfileirados quando todos os executores estão ocupados. Essa métrica não inclui trabalhos que estão aguardando a conclusão
de um trabalho de compilação upstream, portanto, dá uma ideia razoável de quando seu servidor poderá se beneficiar de capacidade extra.

349
Machine Translated by Google

Figura 13.7. Estatísticas de carga do Jenkins

Você pode obter um gráfico semelhante para nós escravos, usando o ícone Load Statistics na página de detalhes do nó escravo.

Outra opção é instalar o plugin Monitoring. Este plugin usa JavaMelody para produzir relatórios HTML abrangentes sobre o
estado do seu servidor de compilação, incluindo CPU e carga do sistema, tempo médio de resposta e uso de memória (veja a
Figura 13.8, “O plugin Jenkins Monitoring”). Depois de instalar este plugin, você pode acessar os gráficos JavaMelody na tela
Gerenciar Jenkins, usando as entradas de menu “Monitoramento do mestre Jenkins/Jenkins” ou “Nós Jenkins/Jenkins”.

350

www.dbooks.org
Machine Translated by Google

Figura 13.8. O plug-in de monitoramento Jenkins

13.4. Fazendo backup de sua configuração


Fazer backup de seus dados é uma prática universalmente recomendada e seu servidor Jenkins não deve ser exceção.
Felizmente, fazer backup do Jenkins é relativamente fácil. Nesta seção, veremos algumas maneiras de fazer isso.

13.4.1. Fundamentos dos backups Jenkins

Na configuração mais simples, tudo que você precisa fazer é fazer backup periodicamente do seu diretório
JENKINS_HOME . Contém todas as configurações de seus trabalhos de construção, configurações de nó escravo e
seu histórico de construção. Isso também funcionará bem enquanto o Jenkins estiver em execução – não há necessidade
de desligar o servidor enquanto faz o backup.

A desvantagem dessa abordagem é que o diretório JENKINS_HOME pode conter uma quantidade muito grande de
dados (consulte a Seção 3.13, “O que há no diretório inicial do Jenkins”). Se isso se tornar um problema, você pode
economizar um pouco não fazendo backup dos seguintes diretórios, que contêm dados que podem ser facilmente
recriados dinamicamente pelo Jenkins:

$JENKINS_HOME/guerra
O arquivo WAR explodido

351
Machine Translated by Google

$JENKINS_HOME/cache
Ferramentas baixadas

$JENKINS_HOME/ferramentas
Ferramentas extraídas

Você também pode ser seletivo sobre o que você faz backup nos dados de seus trabalhos de construção. O diretório $JENKINS_HOME/
jobs contém configuração de trabalho, histórico de construção e arquivos arquivados para cada um de seus trabalhos de construção.
A estrutura de um diretório de trabalho de construção é ilustrada na Figura 13.9, “O diretório de construções”.

Figura 13.9. O diretório de compilações

Para entender como otimizar seus backups do Jenkins, você precisa entender como os diretórios de trabalho de construção são
organizados. Dentro do diretório jobs há um subdiretório para cada trabalho de construção. Este subdiretório contém dois subdiretórios
próprios: builds e workspace. Não há necessidade de fazer backup do diretório do espaço de trabalho , pois ele simplesmente será
restaurado com uma verificação limpa se Jenkins descobrir que está faltando.

O diretório builds , por outro lado, precisa de mais atenção. Este diretório contém o histórico dos resultados da construção e dos
artefatos gerados anteriormente, com um diretório com registro de data e hora para cada

352

www.dbooks.org
Machine Translated by Google

construir. Se não estiver interessado em restaurar o histórico de construção ou artefatos anteriores, não será necessário
armazenar esse diretório. Se estiver, continue lendo! Em cada um desses diretórios, você encontrará o histórico de construção
(armazenado na forma de arquivos XML, como resultados de testes JUnit) e artefatos arquivados. Jenkins usa arquivos XML e
de texto para produzir os gráficos exibidos no painel do trabalho de construção, portanto, se eles forem importantes para você,
armazene esses arquivos. O diretório de archive contém arquivos binários que foram gerados e armazenados por compilações
anteriores. Esses binários podem ou não ser importantes para você, mas podem ocupar muito espaço; portanto, se você excluí-
los de seus backups, poderá economizar uma quantidade considerável de espaço.

Assim como é aconselhável fazer backups frequentes, também é aconselhável testar o procedimento de backup. Com Jenkins,
isso é fácil de fazer. Os diretórios iniciais do Jenkins são totalmente portáteis, então tudo que você precisa fazer para testar
seu backup é extraí-lo para um diretório temporário e executar uma instância do Jenkins nele. Por exemplo, imagine que
extraímos nosso backup para um diretório temporário chamado /tmp/jenkins-backup. Para testar este backup, primeiro configure
o diretório JENKINS_HOME para este diretório temporário:

$ exportar JENKINS_HOME=/tmp/jenkins-backup

Em seguida, basta iniciar o Jenkins em uma porta diferente e ver se funciona:

$ java -jar jenkins.war --httpPort=8888

Agora você pode visualizar o Jenkins em execução nesta porta e certificar-se de que seu backup funcionou corretamente.

13.4.2. Usando o plug-in de backup


A abordagem descrita na seção anterior é simples o suficiente para ser integrada aos procedimentos normais de backup, mas
você pode preferir algo mais específico do Jenkins. O plugin Backup (veja Figura 13.10, “O plugin Jenkins Backup Manager”)
fornece uma interface de usuário simples que você pode usar para fazer backup e restaurar suas configurações e dados do
Jenkins.

Figura 13.10. O plug-in do gerenciador de backup Jenkins

353
Machine Translated by Google

Este plug-in permite configurar e executar backups das configurações do trabalho de construção e do histórico de
construção. A tela de configuração oferece um grande grau de controle sobre exatamente o que você deseja fazer
backup (consulte a Figura 13.11, “Configurando o Jenkins Backup Manager”). Você pode optar por fazer backup apenas
dos arquivos de configuração XML ou fazer backup dos arquivos de configuração e do histórico de construção. Você
também pode optar por fazer backup (ou não) dos artefatos Maven gerados automaticamente (em muitos processos de
construção, eles estarão disponíveis no Enterprise Repository Manager local). Você também pode fazer backup dos
espaços de trabalho (normalmente desnecessários, como discutimos acima) e de quaisquer impressões digitais geradas.

Figura 13.11. Configurando o gerenciador de backup Jenkins

Você pode acionar um backup manualmente na tela do Gerenciador de backup (que pode ser acessada na tela Gerenciar
Jenkins). O backup leva algum tempo e desligará o Jenkins durante o processo (a menos que você desative esta opção
na configuração do backup).

No momento em que este artigo foi escrito, não há como agendar esta operação de dentro do Jenkins, mas você pode
iniciar a operação de backup externamente invocando a URL correspondente (por exemplo, http://localhost:8080/backup/
backup se sua instância do Jenkins for executando localmente na porta 8080). Em um ambiente Unix, por exemplo, isso
normalmente seria agendado como uma tarefa cron usando uma ferramenta como wget ou curl para iniciar o backup.

13.4.3. Backups automatizados mais leves


Se tudo o que você deseja fazer backup é a configuração do trabalho de construção, o plug-in do Backup Manager pode
ser considerado um exagero. Outra opção é usar o plugin Thin Backup, que permite agendar backups completos e
incrementais de seus arquivos de configuração. Como eles não salvam seu histórico de construção ou artefatos, esses
backups são muito rápidos e não há necessidade de desligar o servidor para realizá-los.

Assim como o plugin Backup, este plugin adiciona um ícone à página de configuração do sistema Jenkins. A partir daqui,
você pode configurar e agendar backups de configuração, forçar um backup imediato ou restaurar seu

354

www.dbooks.org
Machine Translated by Google

arquivos de configuração para um estado anterior. A configuração é simples (consulte a Figura 13.12, “Configurando o plugin
Thin Backup”) e envolve simplesmente o agendamento de backups completos e incrementais usando uma sintaxe de tarefa
cron e o fornecimento de um diretório no qual armazenar os backups.

Figura 13.12. Configurando o plugin Thin Backup

Para restaurar uma configuração anterior, basta ir até a página Restaurar e escolher a data da configuração que deseja
restabelecer (veja Figura 13.13, “Restaurando uma configuração anterior”). Depois que a configuração for restaurada ao estado
anterior, será necessário recarregar a configuração do Jenkins do disco ou reiniciar o Jenkins.

Figura 13.13. Restaurando uma configuração anterior

13.5. Arquivando Jobs de Construção

Outra forma de resolver problemas de espaço em disco é excluir ou arquivar projetos que não estão mais ativos.
Arquivar um projeto permite restaurá-lo facilmente mais tarde, caso seja necessário consultar os dados ou artefatos do projeto.
Arquivar um projeto é simples: basta mover o diretório do projeto de construção para fora do diretório do trabalho. É claro que,
normalmente, você primeiro o compactaria em um arquivo ZIP ou tarball.

No exemplo a seguir, queremos arquivar o projeto tweeter-default. Então, primeiro vamos ao diretório de jobs do Jenkins e
criamos um tarball (arquivo compactado) do diretório de jobs de build tweeter-default :

$ cd $JENKINS_HOME/
trabalhos $ ls

355
Machine Translated by Google

gameoflife-default $ tar czf padrão do tweeter

tweeter-default.tgz tweeter-default $ ls

padrão do jogo da vida padrão do tweeter tweeter-default.tgz

Contanto que o projeto que você deseja arquivar não esteja em execução, agora você pode excluir com segurança o diretório do
projeto e mover o arquivo para armazenamento:

$ rm -Rf tweeter padrão


$ mv tweeter-default.tgz /data/archives/jenkins

Depois de fazer isso, você pode simplesmente recarregar a configuração do disco na tela Gerenciar Jenkins (veja Figura 13.14,
“Recarregando a configuração do disco”). O projeto arquivado desaparecerá imediatamente do seu painel.

Figura 13.14. Recarregando a configuração do disco

Em uma máquina Windows, você pode fazer exatamente a mesma coisa criando um arquivo ZIP do diretório do projeto.

13.6. Migrando trabalhos de compilação

Há momentos em que você precisa mover ou copiar trabalhos de construção do Jenkins de uma instância do Jenkins para outra,
sem copiar toda a configuração do Jenkins. Por exemplo, você pode estar migrando seus trabalhos de construção para uma instância
do Jenkins em uma caixa totalmente nova, com detalhes de configuração do sistema que variam da máquina original. Ou você pode
estar restaurando um trabalho de construção antigo que arquivou.

Como vimos, o Jenkins armazena todos os dados necessários para um projeto em um subdiretório do diretório jobs no diretório
inicial do Jenkins. Este subdiretório é fácil de identificar – ele tem o mesmo nome do seu projeto. Aliás, esse é um dos motivos pelos
quais os nomes dos seus projetos realmente não deveriam conter espaços, especialmente se o Jenkins estiver rodando em Unix ou
Linux - isso torna as tarefas de manutenção e administração muito mais fáceis se os nomes dos projetos também forem nomes de
arquivos Unix bem comportados.

Você pode copiar ou mover trabalhos de construção entre instâncias de projetos simplesmente copiando ou movendo os diretórios
de trabalhos de construção para a nova instância do Jenkins. O diretório de tarefas do projeto é independente – contém a
configuração completa do projeto e todo o histórico de construção. É até seguro copiar o trabalho de construção

356

www.dbooks.org
Machine Translated by Google

diretórios para uma instância do Jenkins em execução, mas se você também estiver excluindo-os do servidor original, deverá
encerrar este primeiro. Você nem precisa reiniciar a nova instância do Jenkins para ver os resultados da sua importação –
basta ir para a tela Gerenciar Jenkins e clicar em Recarregar configuração do disco. Isso carregará os novos trabalhos e os
tornará imediatamente visíveis no painel do Jenkins.

Existem algumas dicas, no entanto. Se você estiver migrando seus trabalhos para uma configuração Jenkins totalmente nova,
lembre-se de instalar ou migrar os plug-ins do seu servidor original. Os plugins podem ser encontrados no diretório plugins ,
então você pode simplesmente copiar tudo deste diretório para o diretório correspondente em sua nova instância.

Claro, você pode estar migrando os trabalhos de construção para uma nova instância precisamente porque a configuração do
plugin na caixa original está uma bagunça. Alguns plug-ins do Jenkins podem apresentar alguns bugs às vezes, e você pode
querer migrar para uma instalação limpa com um conjunto bem conhecido e bem definido de plug-ins verificados. Nesse caso,
pode ser necessário retrabalhar algumas configurações do seu projeto depois de importadas.

A razão para isso é simples. Quando você usa um plugin em um projeto, o config.xml do projeto será atualizado com campos
de configuração específicos do plugin. Se por algum motivo você precisar migrar projetos seletivamente para uma instalação
do Jenkins sem esses plugins instalados, o Jenkins não entenderá mais essas partes da configuração do projeto. Às vezes, a
mesma coisa também pode acontecer se as versões do plugin forem muito diferentes nas máquinas e o formato de dados
usado pelo plugin tiver mudado.

Se você estiver migrando jobs para uma instância do Jenkins com uma configuração diferente, também vale a pena ficar de
olho nos logs do sistema. Configurações de plug-in inválidas geralmente informam você por meio de avisos ou exceções.
Embora nem sempre sejam fatais, essas mensagens de erro geralmente significam que o plug-in não funcionará conforme o
esperado ou nem funcionará.

Jenkins fornece alguns recursos úteis para ajudá-lo a migrar as configurações do seu projeto. Se o Jenkins encontrar dados
que considera desatualizados ou inválidos, ele informará isso a você. Na tela Gerenciar Jenkins, você receberá uma
mensagem como a da Figura 13.15, “Jenkins irá informá-lo se seus dados não forem compatíveis com a versão atual”.

Figura 13.15. Jenkins irá informá-lo se seus dados não forem compatíveis com a versão atual

A partir daqui, você pode optar por deixar a configuração como está (caso você reverta para uma versão anterior da sua
instância do Jenkins, por exemplo) ou deixar o Jenkins descartar os campos que não consegue ler.
Se você escolher esta opção, o Jenkins abrirá uma tela contendo mais detalhes sobre o erro, e

357
Machine Translated by Google

pode até ajudar a organizar os arquivos de configuração do seu projeto, se desejar (veja a Figura 13.16, “Gerenciando dados
desatualizados de build jobs”).

Figura 13.16. Gerenciando dados desatualizados de build jobs

Esta tela fornece mais detalhes sobre o projeto que contém os dados duvidosos, bem como o erro exato
mensagem. Isso lhe dá várias opções. Se você tem certeza de que não precisa mais do plugin que originalmente
criou os dados, você pode remover com segurança os campos redundantes clicando no botão Descartar Ilegível
Botão de dados. Alternativamente, você pode decidir que os campos pertencem a um plugin útil que ainda não foi
instalado na nova instância do Jenkins. Neste caso, instale o plugin e tudo ficará bem. Finalmente, você
você sempre pode optar por deixar os dados redundantes e conviver com a mensagem de erro, pelo menos até ter certeza
que você não precisará migrar o trabalho de volta para o servidor antigo algum dia.

No entanto, o Jenkins nem sempre detecta todos os erros ou inconsistências – ainda assim vale a pena manter um
fique de olho nos logs do sistema ao migrar seus trabalhos de construção. Por exemplo, o seguinte é um exemplo real
de um arquivo de log do Jenkins mostrando o que pode acontecer durante o processo de migração:

16 de março de 2010 14:05:06 hudson.util.CopyOnWriteList$ConverterImpl desempacotar


AVISO: Falha ao resolver a classe
com.thoughtworks.xstream.mapper.CannotResolveClassException: hudson.plugins.ciga
me.GamePublisher: hudson.plugins.cigame.GamePublisher
em com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper
.java:68)
em com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper
.java:38)
em com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicP
roxyMapper.java:71)
em com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper
.java:38)

O erro é essencialmente contando nós que isto não consigo encontrar uma aula chamado

hudson.plugins.cigame.GamePublisher. Na verdade, a instalação de destino não possui o CI Game


plugar. E neste caso (como às vezes acontece), nenhuma mensagem de aviso apareceu no Gerenciar
Página Jenkins, então Jenkins não conseguiu corrigir os arquivos de configuração sozinho.

358

www.dbooks.org
Machine Translated by Google

A solução mais simples neste caso seria instalar o plugin CI Game no servidor de destino. Mas e se não quisermos instalar
este plugin? Poderíamos deixar os arquivos de configuração de lado, mas isso pode mascarar erros mais significativos
posteriormente – seria melhor organizá-los.

Nesse caso, precisamos inspecionar e atualizar manualmente os arquivos de configuração do projeto. Nesta caixa Unix, usei
apenas grep para encontrar todos os arquivos de configuração contendo uma referência a “cigame”:

$ cd $JENKINS_HOME/jobs $ grep
cigame */config.xml project-a/config.xml:
project-b/config.xml: project-c/ <hudson.plugins.cigame.GamePublisher/>
config.xml: <hudson.plugins.cigame.GamePublisher/>
<hudson.plugins.cigame.GamePublisher/>

Nestes arquivos config.xml, encontrei a referência ao plugin CI Game em <publishers> sect1 (que é onde geralmente vai a
configuração dos plugins de relatórios):

<conjunto de módulos maven2>


...
<editores>
<hudson.plugins.cigame.GamePublisher/>
<hudson.plugins.claim.ClaimPublisher/>
</editores>
...
</maven2-moduleset>

Para corrigir o problema, tudo o que preciso fazer é remover a linha incorreta:

<conjunto de módulos maven2>


...
<editores>
<hudson.plugins.claim.ClaimPublisher/>
</editores>

...
</maven2-moduleset>

A localização exata dos dados de configuração do plugin irá variar dependendo do plugin, mas em geral os arquivos
config.xml são bastante legíveis e atualizá-los manualmente não é muito difícil.

Portanto, em suma, migrar trabalhos de construção entre instâncias do Jenkins não é tão difícil - você só precisa saber
alguns truques para os casos extremos e, se souber onde procurar, o Jenkins fornece algumas ferramentas interessantes
para tornar o processo mais suave .

13.7. Conclusão
Neste capítulo, examinamos uma série de considerações que você deve estar ciente se seu trabalho for manter seu servidor
Jenkins, incluindo como monitorar o uso do disco e do servidor, como fazer backup de seus trabalhos de construção e
arquivos de configuração do Jenkins, e também como migrar jobs de build e atualizar dados de build com segurança.

359
Machine Translated by Google

www.dbooks.org
Machine Translated by Google

Apêndice A. Automatizando seus


testes unitários e de integração
A.1. Automatizando seus testes com Maven
Maven é uma ferramenta de construção de código aberto popular do mundo Java, que faz uso de práticas como dependências
declarativas, diretórios padrão e ciclos de vida de construção e convenção sobre configuração para encorajar scripts de construção
limpos, de alto nível e de fácil manutenção. A automação de testes é fortemente suportada no Maven. Os projetos Maven usam uma
estrutura de diretório padrão: ele procurará automaticamente testes de unidade em um diretório chamado (por padrão) src/test/java. Há
pouco mais para configurar: basta adicionar uma dependência à estrutura de teste (ou estruturas) que seus testes estão usando, e o
Maven procurará e executará automaticamente os testes JUnit, TestNG ou mesmo Plain Old Java Objects (POJO) contidos neste diretório

estrutura.

No Maven, você executa seus testes de unidade invocando a fase do ciclo de vida do teste , conforme mostrado aqui:

$ mvn teste
[INFO] Procurando projetos...
[INFORMAÇÕES] ----------------------------------------------- -------------------------

[INFO] Construindo modelo de domínio do Tweeter


[INFO] segmento de tarefa: [teste]
[INFORMAÇÕES] ----------------------------------------------- -------------------------
...
-------------------------------------------------- -----

TESTES
-------------------------------------------------- -----

Executando testes com.wakaleo.training.tweeter.domain.TagTest executados: 13, Falhas: 0, Erros: 0,

Ignorados: 0, Tempo decorrido: 0,093 segundos Executando testes com.wakaleo.training.tweeter.domain.TweeterTest executados: 3 , Falhas: 0, Erros: 0,

Ignorados: 0, Tempo decorrido: 0,021 seg. Executando com.wakaleo.training.tweeter.domain.TweeterUserTest

Testes executados: 4, Falhas: 0, Erros: 0, Ignorados: 0, Tempo decorrido: 0,055 seg Executando testes com.wakaleo.training.tweeter.domain.TweetFeeRangeTest

executados: 10, Falhas: 0, Erros: 0, Ignorados: 0, Tempo decorrido: 0,051 seg Executando testes

com.wakaleo.training.tweeter.domain.HamcrestTest executados : 8, Falhas: 0, Erros: 0, Ignorados: 0, Tempo decorrido: 0,023 seg.

Resultados :

Testes executados: 38, Falhas: 0, Erros: 0, Ignorados: 0

Além de executar seus testes e falhar na construção se algum dos testes falhar, o Maven produzirá um conjunto de relatórios de teste
(novamente, por padrão) no diretório target/surefire-reports , nos formatos XML e texto. Para nossos propósitos de CI, são os arquivos
XML que nos interessam, já que Jenkins é capaz de entender e analisar esses arquivos para seus relatórios de CI:

$ ls target/surefire-reports/*.xml
Machine Translated by Google

target/surefire-reports/TEST-com.wakaleo.training.tweeter.domain.HamcrestTest.xml target/surefire-reports/TEST-
com.wakaleo.training.tweeter.domain.TagTest.xml target/surefire-reports/TEST-
com.wakaleo.training.tweeter.domain.TweetFeeRangeTest.xm target/surefire-reports/TEST-
com.wakaleo.training.tweeter.domain.TweeterTest.xml target/surefire-reports/TEST-com.wakaleo.training.tweeter.
domínio.TweeterUserTest.xml

O Maven define duas fases distintas de teste: testes unitários e testes de integração. Os testes unitários devem ser rápidos
e leves, fornecendo uma grande quantidade de feedback de teste no menor tempo possível. Os testes de integração são
mais lentos e complicados e muitas vezes exigem que a aplicação seja construída e implantada em um servidor (mesmo
que seja incorporado) para realizar testes mais completos. Ambos os tipos de testes são importantes e, para um ambiente
de Integração Contínua bem projetado, é importante poder distinguir entre eles. A compilação deve garantir que todos os
testes unitários sejam executados inicialmente – se um teste unitário falhar, os desenvolvedores deverão ser notificados
rapidamente. Somente se todos os testes unitários forem aprovados é que vale a pena realizar os testes de integração mais
lentos e pesados.

No Maven, os testes de integração são executados durante a fase do ciclo de vida do teste de integração , que você pode
invocar executando mvn teste de integração ou (mais simplesmente) mvn verify. Durante esta fase, é fácil configurar o
Maven para iniciar sua aplicação web em um servidor web Jetty incorporado ou para empacotar e implantar sua aplicação
em um servidor de teste, por exemplo. Seus testes de integração podem então ser executados no aplicativo em execução.
A parte complicada, entretanto, é dizer ao Maven como distinguir entre seus testes de unidade e seus testes de integração,
para que eles só sejam executados quando uma versão em execução do aplicativo estiver disponível.

Existem várias maneiras de fazer isso, mas no momento em que este artigo foi escrito não havia uma abordagem padrão
oficial usada em todos os projetos Maven. Uma estratégia simples é usar convenções de nomenclatura: todos os testes de
integração podem terminar em “IntegrationTest” ou ser colocados em um pacote específico. A classe a seguir usa uma
dessas convenções:

classe pública AccountIntegrationTest {

@Teste
public void cashWithdrawalShouldDeductSumFromBalance() lança Exception {Conta conta = nova conta();
conta.makeDeposit(100);
conta.makeCashWithdraw(60);

assertThat(account.getBalance(), is(40));
}
}

No Maven, os testes são configurados por meio do plugin maven-surefire- plugin. Para garantir que o Maven execute
esses testes apenas durante a fase de teste de integração , você pode configurar este plugin conforme mostrado aqui:

<projeto>
...
<construir>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>

362

www.dbooks.org
Machine Translated by Google

<configuration> <skip>true</
skip>ÿ </configuration>
<execuções>

<execução>ÿ
<id>testes unitários</id>
<phase>test</phase> <goals>
<goal>test</
goal> </goals> <configuration>
<skip>false</
skip> <excludes>

<exclude>**/*IntegrationTest.java</exclude> </excludes>

</configuration> </execution>

<execução>ÿ
<id>testes de integração</id> <phase>teste
de integração</phase> <goals> <goal>teste</goal> </
goals>
<configuration> <skip>falso</
skip> <inclui>

<include>**/*IntegrationTest.java</include>
</inclui>
</configuration> </execution>

</executions> </plugin>

...

ÿ Ignorar todos os testes por padrão — isso desativa a configuração de teste padrão do Maven. ÿ
Durante a fase de teste unitário, execute os testes, mas exclua os testes de integração. ÿ
Durante a fase de teste de integração, execute os testes, mas inclua apenas os testes de integração.

Isso garantirá que os testes de integração sejam ignorados durante a fase de teste de unidade e executados apenas durante
a fase de teste de integração.

Se não quiser impor restrições indesejadas aos nomes de suas classes de teste, você poderá usar nomes de pacotes. No
projeto ilustrado na Figura A.1, “Um projeto contendo classes de teste de nomes livres”, todos os testes funcionais foram
colocados em um pacote chamado webtests. Não há nenhuma restrição nos nomes dos testes, mas estamos usando
objetos de página para modelar a interface de usuário do nosso aplicativo, portanto, também nos certificamos de que
nenhuma classe no pacote de páginas (abaixo do pacote webtests ) seja tratada como teste.

363
Machine Translated by Google

Figura A.1. Um projeto contendo classes de teste com nomes livres

No Maven, poderíamos fazer isso com a seguinte configuração:

<plugin>
<artifactId>maven-surefire-plugin</artifactId> <configuration>
<skip>true</skip>

</configuration>
<execuções>
<execução>
<id>testes unitários</id>
<phase>test</phase>
<goals>
<goal>test</goal> </
goals>
<configuration>
<skip>false</skip>
<excludes>
<exclude>**/webtests/*.java</exclude> </excludes>

</configuration> </
execution>
<execução>
<id>testes de integração</id>
<phase>teste de integração</phase> <goals>

<goal>teste</goal> </goals>

<configuration>
<skip>falso</skip>
<includes>

364

www.dbooks.org
Machine Translated by Google

<include>**/webtests/*.java</include> </includes>

<exclui>
<exclude>**/pages/*.java</exclude> </excludes>

</configuration> </
execution>
</executions> </
plugin>

TestNG atualmente tem suporte mais flexível para grupos de teste do que JUnit. Se estiver usando TestNG, você pode
identificar seus testes de integração usando grupos TestNG. No TestNG, classes de teste ou métodos de teste podem ser
marcados usando o atributo groups da anotação @Test , conforme mostrado aqui:

@Test(grupos = { "teste de integração" }) public void


cashWithdrawalShouldDeductSumFromBalance() lança exceção {
Conta conta = nova conta();
conta.makeDeposit(100);
conta.makeCashWithdraw(60);
assertThat(account.getBalance(), is(40));
}

Usando o Maven, você poderia garantir que esses testes fossem executados apenas durante a fase de teste de integração
usando a seguinte configuração:

<projeto>
...
<construir>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip>

</configuration>
<execuções>
<execução>
<id>testes unitários</id>
<phase>test</phase> <goals>
<goal>test</
goal> </goals> <configuration>
<skip>false</
skip>
<excludedGroups>testes de
integração </excludedGroups>ÿ
</configuration> </
execution>
<execução>
<id>testes de integração</id> <phase>teste
de integração</phase> <goals> <goal>teste</goal>
</goals>
<configuration> <skip>falso</
skip>

365
Machine Translated by Google

<groups>testes de integração</groups>ÿ
</configuration> </
execution>
</executions> </
plugin>
...

ÿ Não execute o grupo de testes de integração durante a fase de teste. ÿ


Execute apenas os testes do grupo de testes de integração durante a fase de teste de integração.

Muitas vezes faz sentido executar seus testes em paralelo sempre que possível, pois isso pode acelerá-los significativamente
(veja Seção 6.9, “Ajuda! Meus testes estão muito lentos!”). Os testes paralelos são particularmente intensivos com testes de
execução lenta que utilizam muito IO, disco ou acesso à rede (como testes web), o que é conveniente, pois estes são
precisamente o tipo de testes que normalmente queremos acelerar.

TestNG oferece bom suporte para testes paralelos. Por exemplo, usando TestNG, você pode configurar seus métodos de
teste para serem executados em paralelo em dez threads simultâneos como este:

<plugin>
<groupId>org.apache.maven.plugins</groupId> <artifactId>maven-
surefire-plugin</artifactId> <versão>2.5</versão>

<configuração>
<parallel>métodos</parallel>
<threadCount>10</threadCount> </
configuration> </plugin>

A partir do JUnit 4.7, você também pode executar testes JUnit em paralelo usando uma configuração semelhante. Na
verdade, a configuração mostrada acima funcionará no JUnit 4.7 em diante.

Você também pode definir o item de configuração <parallel> para classes em vez de métodos, que tentarão executar as
classes de teste em paralelo, em vez de cada método. Isso pode ser mais lento ou mais rápido, dependendo do número de
classes de teste que você possui, mas pode ser mais seguro para alguns casos de teste não projetados tendo em mente a
simultaneidade.

A quilometragem varia, então você deve experimentar os números para obter os melhores resultados.

A.2. Automatizando seus testes com Ant


Configurar testes automatizados no Ant também é relativamente fácil, embora exija um pouco mais de detalhamento do que
no Maven. Em particular, o Ant não vem empacotado com as bibliotecas JUnit ou tarefas Ant prontas para uso, então você
mesmo deve instalá-las em algum lugar. A abordagem mais portátil é usar uma ferramenta de gerenciamento de
dependências, como Ivy, ou colocar os arquivos JAR correspondentes em um diretório dentro do seu projeto.
estrutura.

Para executar seus testes no Ant, você chama a tarefa <junit> . Uma configuração típica compatível com Jenkins é mostrada
neste exemplo:

366

www.dbooks.org
Machine Translated by Google

<nome da propriedade="build.dir" value="target" /> <nome da


propriedade="java.classes" value="${build.dir}/classes" /> <nome da propriedade="test.classes"
valor= "${build.dir}/test-classes" /> <property name="test.reports" value="${build.dir}/test-reports" />
<property name="lib" value="$ {build.dir}/lib" />

<caminho id="test.classpath">ÿ
<pathelement location="/Users/johnsmart/Projects/Books/jenkins-the-definitive-guide/hudsonbook-con <pathelement location="${java.classes}" />
<pathelement location="${lib}" / > </caminho>

<target name="test" depende="test-compile">


<junit haltonfailure="no" failedproperty="failed">ÿ
<classpath>ÿ <path
refid="test.classpath" /> <pathelement location="$
{test.classes}" /> </classpath> <formatter type="xml" />ÿ
<batchtest
fork="yes" forkmode="perBatch"ÿ
todir="${test.reports}"> <conjunto de arquivos dir="${test.src}">ÿ

<include name="**/*Test*.java" /> </fileset> </


batchtest> </
junit> <fail

message="TEST FAILURE" if="failed" />ÿ </target>

ÿ Precisamos configurar um classpath contendo os arquivos JAR junit e junit-ant , bem como as classes do
aplicativo e quaisquer outras dependências que o aplicativo precise para compilar e executar. ÿ Os
próprios testes são executados aqui. A opção haltonfailure é usada para fazer com que a construção falhe
imediatamente se algum teste falhar. Em um ambiente de Integração Contínua, isso não é exatamente o que
queremos, pois também precisamos obter os resultados para quaisquer testes subsequentes. Portanto,
definimos esse valor como no e usamos a opção failproperty para forçar a falha da compilação assim
que todos os testes forem concluídos. ÿ O classpath precisa conter as bibliotecas JUnit, as classes da sua aplicação e suas dependê
e suas classes de teste compiladas.
ÿ A tarefa Junit Ant pode produzir relatórios de texto e XML, mas para Jenkins, precisamos apenas do
XML.
ÿ A opção fork executa seus testes em uma JVM separada. Geralmente, isso é uma boa ideia, pois pode evitar
problemas do carregador de classe relacionados a conflitos com as próprias bibliotecas do Ant. No entanto, o
comportamento padrão da tarefa JUnit Ant é criar uma nova JVM para cada teste, o que retarda significativamente os testes.
A opção perBatch é melhor, pois cria apenas uma nova JVM para cada lote de testes.
ÿ Você define os testes que deseja executar em um elemento do conjunto de arquivos. Isso proporciona muita
flexibilidade e facilita a definição de outros alvos para diferentes subconjuntos de testes (integração, web e
assim por diante). ÿ Forçar a falha da compilação após a conclusão dos testes, se algum deles falhar.

Se você preferir TestNG, o Ant também é bem suportado aqui. Usando TestNG com o exemplo anterior, você
poderia fazer algo assim:

367
Machine Translated by Google

<nome da propriedade="build.dir" value="target" /> <nome da


propriedade="java.classes" value="${build.dir}/classes" /> <nome da propriedade="test.classes"
valor= "${build.dir}/test-classes" /> <property name="test.reports" value="${build.dir}/test-reports" />
<property name="lib" value="$ {build.dir}/lib" />

<path id="test.classpath"> <pathelement


location="${java.classes}" /> <pathelement location="${lib}" /> </
path>

<taskdef resource="testngtasks" classpath="lib/testng.jar"/>

<target name="test" depende="test-compile"> <testng


classpathref="test.classpath"
outputDir="${testng.report.dir}" haltonfailure="no"

failproperty="failed"> <classfileset dir="$


{test.classes}"> <include name="**/*Test*.class" />

</classfileset> </testng>
<fail
message="TEST FAILURE" if="failed" /> </target>

TestNG é uma biblioteca de testes muito flexível e a tarefa TestNG tem muito mais opções do que isso. Por exemplo, para executar
apenas testes definidos como parte do grupo “teste de integração” que vimos anteriormente, poderíamos fazer o seguinte:

<target name="integration-test" depende="test-compile">


<testng classpathref="test.classpath" groups="integration-
test" outputDir="${testng.report.dir}"
haltonfailure="no"

failproperty="failed"> <classfileset dir="$


{test.classes}"> <include name="**/*Test*.class" />

</classfileset> </testng>
<fail
message="TEST FAILURE" if="failed" /> </target>

Ou para executar seus testes em paralelo, usando quatro threads simultâneas, você poderia fazer isto:

<target name="integration-test" depende="test-compile">


<testng classpathref="test.classpath"
paralelo =
"verdadeiro" threadCount = 4
outputDir="${testng.report.dir}" haltonfailure="no"

failproperty="failed"> <classfileset dir="$


{test.classes}"> <include name="**/*Test*.class" />

368

www.dbooks.org
Machine Translated by Google

</classfileset> </
testng> <fail
message="TEST FAILURE" if="failed" /> </target>

369

Você também pode gostar