Skip to content

Commit 6bd779f

Browse files
Jaime Salas ZancadaJaime Salas Zancada
authored andcommitted
added demo using Docker plug-in
1 parent 7902064 commit 6bd779f

File tree

1 file changed

+377
-0
lines changed

1 file changed

+377
-0
lines changed
Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
# Demo 1
2+
3+
Corriendo pipelines con Docker.
4+
5+
## Pre-reqs
6+
7+
Ejecutar Jenkins en [Docker](https://www.docker.com/products/docker-desktop):
8+
9+
```bash
10+
$ ./start_jenkins.sh <jenkins-image> <jenkins-network> <jenkins-volume-certs> <jenkins-volume-data>
11+
```
12+
13+
Antes de comenazr borrar las pipelines anetriores
14+
15+
## 1.1 Usando un contenedor como build agent
16+
17+
18+
Create a new directory *05_declarative_pipelines/src_tmp/jenkins-demos-review/02*. Unzip code from `05_declarative_pipelines` directory
19+
20+
```bash
21+
$ unzip code.zip -d ./src_temp/jenkins-demos-review/02
22+
```
23+
24+
Create `02/demo1/1.1/Jenkinsfile`
25+
26+
```groovy
27+
pipeline {
28+
agent {
29+
docker {
30+
image 'node:alpine3.12'
31+
}
32+
}
33+
stages {
34+
stage('Verify') {
35+
steps {
36+
sh '''
37+
node --version
38+
npm version
39+
'''
40+
sh 'printenv'
41+
sh 'ls -l "$WORKSPACE"'
42+
}
43+
}
44+
stage('Build') {
45+
steps {
46+
dir("$WORKSPACE/02/src") {
47+
sh '''
48+
npm install
49+
npm build
50+
'''
51+
}
52+
}
53+
}
54+
stage('Unit Test') {
55+
steps {
56+
dir("$WORKSPACE/02/src") {
57+
sh 'npm test'
58+
}
59+
}
60+
}
61+
}
62+
}
63+
```
64+
65+
Log into Jenkins at http://localhost:8080 with `lemoncode`/`lemoncode`.
66+
67+
- New item, pipeline, `demo1-1`
68+
- Select pipeline from source control
69+
- Git - https://github.com/JaimeSalas/jenkins-pipeline-demos
70+
- Path to Jenkinsfile - `02/demo1/1.1/Jenkinsfile`
71+
- Run
72+
73+
> Walk through the [Jenkinsfile](./02/demo1/1.1/Jenkinsfile)
74+
75+
```groovy
76+
agent {
77+
docker {
78+
image 'node:alpine3.12'
79+
}
80+
}
81+
```
82+
83+
Esta parte es ahora diferente, estamos especificando que el agante es un `contenedor de Docker`, y la imagen `node:alpine3.12` es la que queremos usar. Lo que ocurre cuando esta build arranca, Jenkins arranca un contenedor utilizando como base esta imagen.
84+
85+
Todos los `shell commands` son ejecutados dentro del contenedor.
86+
87+
Puedo usar `Docker` como mi agnete de build , y no necesito tener una máquina con `node` instalado. Culaquier servidor de Jenkins, con `Docker` instalado puede levantar una agente con `node` y ejecutar toda la pipeline dentro del contenedor, con Jenkins tomando la responsabilidad de mover los ficheros necesarios y estableciendo el entorno del contenedor por mi.
88+
89+
## 1.2 Custom container agents
90+
91+
* Crear `02/Dockerfile`
92+
93+
```Dockerfile
94+
FROM node:alpine3.12 as builder
95+
96+
WORKDIR /build
97+
98+
COPY ./src .
99+
100+
RUN npm install
101+
102+
RUN npm run build
103+
104+
FROM node:alpine3.12 as application
105+
106+
WORKDIR /opt/app
107+
108+
COPY ./src/package.json .
109+
110+
COPY ./src/package-lock.json .
111+
112+
COPY --from=builder /build/app .
113+
114+
RUN npm i --only=production
115+
116+
ENTRYPOINT ["node", "app.js"]
117+
```
118+
119+
120+
* Create `02/demo1/1.2/Jenkinsfile`
121+
122+
```groovy
123+
pipeline {
124+
agent {
125+
dockerfile {
126+
dir '02'
127+
}
128+
}
129+
stages {
130+
stage('Verify') {
131+
steps {
132+
sh'''
133+
node --version
134+
npm version
135+
'''
136+
}
137+
}
138+
stage('Smoke Test') {
139+
steps {
140+
sh 'docker run jaimesalas/jenkins-pipeline-demos:0.0.1'
141+
}
142+
}
143+
}
144+
}
145+
```
146+
147+
Push changes
148+
149+
- Copy item, `demo1-2` from `demo1-1`
150+
- Path to Jenkinsfile `02/demo1/1.2/Jenkinsfile`
151+
- Run - fails
152+
153+
> Walk through the [Dockerfile](../Dockerfile) and the [Jenkinsfile](./02/demo1/1.2/Jenkinsfile)
154+
155+
```groovy
156+
pipeline {
157+
agent {
158+
dockerfile {
159+
dir '02'
160+
}
161+
}
162+
stages {
163+
stage('Verify') {
164+
steps {
165+
sh'''
166+
node --version
167+
npm version
168+
'''
169+
}
170+
}
171+
stage('Build') {
172+
steps {
173+
sh 'docker build -t jaimesalas/jenkins-pipeline-demos:0.0.1 .'
174+
}
175+
}
176+
stage('Smoke Test') {
177+
steps {
178+
sh 'docker run jaimesalas/jenkins-pipeline-demos:0.0.1'
179+
}
180+
}
181+
}
182+
}
183+
```
184+
185+
186+
1. En el `agent block` estamos especificando un `Dockerfile`, le estamos diciendo a Jenkins que es un Dockerfile dentro de nuestro repo, en el directorio `02`, y quiero construir una imagen a partir de ese `Dockerfile`. Si inspeccionamos este `Dockerfile` nos damos cuenta de que se trata de una imagen para construir una aplicación, y Jenkins no esta esperando esto.
187+
188+
But what people often do when they're looking at this approach is they get confused as to what that `Dockerfile` is meant to do. So if I look at that `Dockerfile`, this `Dockerfile` is actually a full build of my project.
189+
190+
Esto crea confusión acerca de que hace este `Dockerfile`. Este `Dockerfile` es la `build` completa de mi proyecto.
191+
192+
Comienza desde `node:alpine3.12` e instala los paquetes y realiza una build. Después empaquete la aplicación instalando sólo las dependencias de producción, creando una imagen de Docker que representa nuestra aplicaicón. Y esto no es lo que espera Jenkins. Cuando Jenkins nos ofrece la opción de fichero Docker, dentro del agente arranca una imagen para ser usada como `build agent` no correr la aplicación.
193+
194+
En esta pipeline estamos pensando que pedimos a Jenkinsque compile la aplicación, usando el `Dockerfile` en el repositorio, y después usar `verify` para imprimir node y npm y por último ejecutar un smoke test ejecutando el contenedor previamente generado.
195+
196+
But these are separate things, the image that was built as part of the `Dockerfile` that's an SDK may just not meant to be used by Jenkins taken part of your application.
197+
198+
Pero esto son cosas separadas, la imagen construida a como parte del `Dockerfile`, para construir la aplicación, no esta pensada para ser parte de la aplicación.
199+
200+
So it's going to see how that looks. So if we check this build its failed as expected, we go and look at the output. I could see all the lines for my `Dockerfile` being executed, and then I get these really weird Jenkins error messages telling me it is trying to do something with the container on.
201+
202+
La build falla como esperabamos, echemos un ojo. Podemos ver todas las líneas ejecutadas del `Dockerfile`, y después vemos este mensaje que nos dice que tenemos un fallo al intentar ejecutar el contenedor.
203+
204+
```
205+
[Pipeline] withDockerContainer
206+
Jenkins seems to be running inside container c61967b546156925d074ad58416a569ad9155a1826bd597e25ca2574401b0462
207+
but /var/jenkins_home/workspace/demo1-2 could not be found among []
208+
but /var/jenkins_home/workspace/demo1-2@tmp could not be found among []
209+
$ docker run -t -d -u 1000:1000 -w /var/jenkins_home/workspace/demo1-2 -v /var/jenkins_home/workspace/demo1-2:/var/jenkins_home/workspace/demo1-2:rw,z -v /var/jenkins_home/workspace/demo1-2@tmp:/var/jenkins_home/workspace/demo1-2@tmp:rw,z -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** -e ******** f917174c9fbddb13d878ba8d5720b4002083488f cat
210+
$ docker top 22e164faebd0bffd3ffa850e62353e97099aef48d4d4fa1616622e45957f8825 -eo pid,comm
211+
[Pipeline] // withDockerContainer
212+
[Pipeline] }
213+
[Pipeline] // withEnv
214+
[Pipeline] }
215+
[Pipeline] // node
216+
[Pipeline] End of Pipeline
217+
[Checks API] No suitable checks publisher found.
218+
java.io.IOException: Failed to run top '22e164faebd0bffd3ffa850e62353e97099aef48d4d4fa1616622e45957f8825'. Error: Error response from daemon: Container 22e164faebd0bffd3ffa850e62353e97099aef48d4d4fa1616622e45957f8825 is not running
219+
```
220+
221+
La razón por la que falla es que Jenkins está tratando de ejecutar el contenedor como un `build agent` pero el contenedor ha sido empaquetado para ejecutar mi aplicación, así que no existe ningún `build agent`.
222+
223+
> Walk through the fixed [Dockerfile.node](../Dockerfile.node) and [Jenkinsfile.fixed](./1.2/Jenkinsfile.fixed)
224+
225+
* Crear `Dockerfile.node`
226+
227+
```Dockerfile
228+
FROM node:alpine3.12 as builder
229+
230+
ENV LEMONCODE_VAR=lemon
231+
```
232+
233+
* Y creamos `02/demo1/1.2/Jenkinsfile.fixed` de la siguiente manera:
234+
235+
```groovy
236+
pipeline {
237+
agent {
238+
dockerfile {
239+
dir '02'
240+
filename 'Dockerfile.node'
241+
}
242+
}
243+
stages {
244+
stage('Verify') {
245+
steps {
246+
sh '''
247+
node --version
248+
npm version
249+
'''
250+
sh 'printenv'
251+
sh 'ls -l "$WORKSPACE"'
252+
}
253+
}
254+
stage('Build') {
255+
steps {
256+
dir("$WORKSPACE/02/src") {
257+
sh '''
258+
npm install
259+
npm build
260+
'''
261+
}
262+
}
263+
}
264+
stage('Unit Test') {
265+
steps {
266+
dir("$WORKSPACE/02/src") {
267+
sh 'npm test'
268+
}
269+
}
270+
}
271+
}
272+
}
273+
```
274+
275+
```groovy
276+
agent {
277+
dockerfile {
278+
dir '02'
279+
filename 'Dockerfile.node' // [1]
280+
}
281+
}
282+
```
283+
284+
1. Este `Dockerfile` sirve para personalizar el entorno de build, por ejemplo aquí lo hemos utilizado para incluir una variable nueva de entorno.
285+
286+
- Change Jenkinsfile to `02/demo1/1.2/Jenkinsfile.fixed`
287+
- Run again
288+
289+
## 1.3 Docker pipeline plugin
290+
291+
* Crear `02/demo1/1.3/Jenkinsfile`
292+
293+
```groovy
294+
def image
295+
296+
pipeline {
297+
agent any
298+
stages {
299+
stage('Build') {
300+
steps {
301+
script {
302+
image = docker.build("jaimesalas/jenkins-pipeline-demos:0.0.1", "--pull -f 02/Dockerfile 02")
303+
}
304+
}
305+
}
306+
stage('Smoke Test') {
307+
steps {
308+
script {
309+
container = image.run()
310+
container.stop()
311+
}
312+
}
313+
}
314+
stage('Push') {
315+
steps {
316+
script {
317+
withDockerRegistry([credentialsId: "docker-hub", url: ""]) {
318+
image.push()
319+
}
320+
}
321+
}
322+
}
323+
}
324+
}
325+
```
326+
327+
- Credentials in Jenkins - Docker Hub
328+
- Copy item, `demo1-3` from `demo1-1`
329+
- Path to Jenkinsfile `02/demo1/1.3/Jenkinsfile`
330+
- Run
331+
332+
> Walk through the [Jenkinsfile](.02/demo1/1.3/Jenkinsfile) and [Dockerfile](../Dockerfile)
333+
334+
```groovy
335+
def image
336+
337+
pipeline {
338+
agent any
339+
stages {
340+
stage('Build') {
341+
steps {
342+
script {
343+
image = docker.build("jaimesalas/jenkins-pipeline-demos:0.0.1", "--pull -f 02/Dockerfile 02") // [1]
344+
}
345+
}
346+
}
347+
stage('Smoke Test') {
348+
steps {
349+
script {
350+
container = image.run() // [2]
351+
container.stop()
352+
}
353+
}
354+
}
355+
stage('Push') {
356+
steps {
357+
script {
358+
withDockerRegistry([credentialsId: "docker-hub", url: ""]) { // [3]
359+
image.push()
360+
}
361+
}
362+
}
363+
}
364+
}
365+
}
366+
```
367+
368+
Aquí estamos usando `Docker Pipeline plug-in` que nos da un gran control sobre la interacción de `Jenkins` y el `Docker engine`.
369+
370+
1. Usamos el objeto `docker` el cuál es parte de `Docker Pipeline plug-in`, y ejecutamos el método `build`, diciendo el nombre de la imagen de Docker y donde encontrar el `Dockerfile`
371+
2. Ejecutamos un contenedor generado a partir del paso previo.
372+
3. En el último paso publicamos esa imagen
373+
374+
## Adding Jenkins credentials
375+
376+
> https://www.jenkins.io/doc/book/using/using-credentials/#:~:text=From%20the%20Jenkins%20home%20page,Add%20Credentials%20on%20the%20left.
377+
> https://appfleet.com/blog/building-docker-images-to-docker-hub-using-jenkins-pipelines/#:~:text=On%20Jenkins%20you%20need%20to,this%20credential%20from%20your%20scripts.

0 commit comments

Comments
 (0)