Antecedentes: Jenkins está sendo executado dentro de um contêiner docker, o que funciona muito bem, mas por design queremos que todos os processos de construção sejam executados dentro de contêineres docker para minimizar o software instalado dentro do contêiner Jenkins.
Problema: como faço para construir um processo de três estágios usando dois contêineres docker diferentes, onde todas as três etapas compartilham arquivos?
Etapa 1: construir
- compilação npm
Etapa 2: teste
- teste npm`
Etapa 3: execute a implantação de código AWS
- aws implantar push --nome do aplicativo nome do aplicativo --s3-location s3://my-bucket/nome do aplicativo --ignore-hidden-files
- aws implantar create-deployment --nome do aplicativo nome do aplicativo --s3-location bucket=meu-bucket,key=nome do aplicativo,bundleType=zip --deployment-group-name dg
Como divido o arquivo Jenkins em vários estágios e compartilho a saída do primeiro estágio para os outros estágios?
Jenkinsfile simples de dois estágios
pipeline {
agent {
docker {
image 'node:10.8.0'
}
}
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
}
Mas, quando adiciono na terceira etapa, as coisas ficam mais interessantes, já que não posso usar uma imagem docker global (agente)
pipeline {
agent none
stages {
stage('Build') {
agent {
docker { image 'node:10.8.0' }
}
steps {
sh 'npm install'
}
}
stage('Test') {
agent {
docker { image 'node:10.8.0' }
}
steps {
sh 'npm test'
}
}
stage('Deploy') {
agent {
docker { image 'coreos/awscli' }
}
steps {
sh 'echo "Deploying to AWS"'
sh 'aws help'
}
}
}
}
Acima, o 'teste npm' falha porque os resultados do estágio de construção são perdidos. E a implantação do código não funcionaria porque todos os artefatos de construção foram perdidos.
Uma solução alternativa para fazer o teste funcionar é ter um estágio 'BuildAndTest' que usa uma imagem, mas isso perde algumas das vantagens de etapas separadas.
pipeline {
agent none
stages {
stage('Build And Test') {
agent {
docker { image 'node:10.8.0' }
}
steps {
sh 'npm install'
sh 'npm test'
}
}
stage('Deploy') {
agent {
docker { image 'coreos/awscli' }
}
steps {
sh 'echo "Deploying to AWS"'
sh 'aws help'
}
}
}
}
Uma outra solução (super feia) é criar uma imagem personalizada que tenha o node e o aws instalados, mas isso significa que toda vez que migrarmos para uma versão mais recente do node e/ou do aws, teremos que criar outra imagem docker com a versão atualizada , quando na verdade são tarefas completamente separadas.
A outra solução é montar uma imagem compartilhada entre todas as instâncias, mas como faço para criar uma imagem 'temporária' que seja compartilhada apenas para esta compilação e que seja excluída após a conclusão da compilação?
Responder1
Logo depois de postar a pergunta, encontrei um artigo de um desenvolvedor do Jenkins
https://jenkins.io/blog/2018/07/02/whats-new-declarative-piepline-13x-sequential-stages/
Isto é o que eu inventei
pipeline {
agent none
stages {
stage('Build and Test') {
agent {
docker 'node:10.8.0'
}
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
post {
success {
stash name: 'artifacts', includes: "node_modules/**/*"
}
}
}
stage('Deploy') {
agent {
docker 'coreos/awscli'
}
steps {
unstash 'artifacts'
sh 'echo "Deploying to AWS"'
sh 'aws help'
}
}
}
}
Jenkins agora permite vários estágios dentro do declarativo, e eu não sabia sobre os comandos 'stash/unstash', que funcionam muito bem para mim.