29/04/2019 - DOCKER, GIT, JENKINS
In this example we are going to create a full CI/CD (Continuous Integration/Continuous Delivery) pipeline with Jenkins to work with a Dockerised application. Our Jenkinsfile will depend on Makefile commands. See below the pipeline stages.
This runs pipeline when a new feature/*
branch gets created in GitHub or a new feature/*
push event occurs.
> Build > Test > Destroy
This runs pipeline when any branch gets merged into origin/develop
branch in GitHub. This pipeline involves deployment stage but only for Staging environment. If it was origin/master
branch then the deployment stage would involve Production environment.
> Build > Test > Push > Destroy > Deploy
Note: When we build the docker image of the application, the application code is being baked into the image so all we want to include in the image is the necessary files and folders. This is to keep the image size as small as possible. All the other files and folders listed in .dockerignore
file are ignored.
.
├── cicd
│ ├── merge
│ │ └── develop
│ │ └── Jenkinsfile
│ └── push
│ └── feature
│ └── Jenkinsfile
├── docker
│ ├── dev
│ │ ├── docker-compose.yml
│ │ ├── Makefile
│ │ └── php
│ │ └── Dockerfile
│ └── stag
│ ├── docker-compose.yml
│ ├── Makefile
│ └── php
│ └── Dockerfile
├── .dockerignore
├── .gitignore
├── readme.md
└── src
└── test.php
pipeline {
agent any
options {
skipDefaultCheckout(true)
}
stages {
stage('Git') {
steps {
echo '> Checking out the Git version control ...'
checkout scm
}
}
stage('Build') {
steps {
echo '> Building the docker images ...'
sh 'make -sC docker/stag build'
}
}
stage('Test') {
steps {
echo '> Testing the docker containers ...'
sh 'make -sC docker/stag test'
}
}
stage('Push') {
steps {
echo '> Pushing the docker images ...'
sh 'make -sC docker/stag push'
}
}
stage('Destroy') {
steps {
echo '> Destroying the docker artifacts ...'
sh 'make -sC docker/stag destroy'
}
}
stage('Deploy') {
steps {
echo '> Deploying the application images ...'
}
}
}
}
pipeline {
agent any
options {
skipDefaultCheckout(true)
}
stages {
stage('Git') {
steps {
echo '> Checking out the Git version control ...'
checkout scm
}
}
stage('Build') {
steps {
echo '> Building the docker containers ...'
sh 'make -sC docker/dev build'
}
}
stage('Test') {
steps {
echo '> Running the application tests ...'
sh 'make -sC docker/dev test'
}
}
stage('Destroy') {
steps {
echo '> Destroying the docker artifacts ...'
sh 'make -sC docker/dev destroy'
}
}
}
}
FROM alpine:3.9
RUN apk add --no-cache php7
WORKDIR /app
RUN rm -rf /var/cache/apk/*
CMD tail -f /dev/null
version: "3"
services:
mini_php:
build:
context: "php"
hostname: "mini-php"
volumes:
- "../../:/app:consistent"
PHP_SERVICE := mini_php
build:
@docker-compose up -d --build
test:
@docker-compose exec -T $(PHP_SERVICE) php src/test.php
destroy:
@docker-compose down --rmi=all
@docker system prune --force
all:
@make -s build test destroy
config:
@docker-compose config
FROM alpine:3.9
RUN apk add --no-cache php7
COPY . /app
WORKDIR /app
RUN rm -rf /var/cache/apk/*
CMD tail -f /dev/null
version: "3"
services:
mini_php:
build:
context: "../.."
dockerfile: "docker/stag/php/Dockerfile"
image: "inanzzz/mini_php:latest"
PHP_SERVICE := mini_php
build:
@docker-compose build --no-cache
test:
@docker-compose run -T --rm $(PHP_SERVICE) php src/test.php
push:
@docker-compose push
destroy:
@docker-compose down --rmi=all
@docker system prune --force
all:
@make -s build test push destroy
config:
@docker-compose config
<?php
echo 'success';
.git/
.idea/
.DS_Store/
.gitignore
.dockerignore
readme.md
composer.json
composer.lock
docker/
.idea/
.DS_Store/
Any command below is run on Jenkins server.
vagrant$ sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common
vagrant$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
vagrant$ sudo apt-key fingerprint 0EBFCD88
vagrant$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
vagrant$ sudo apt-get update
vagrant$ sudo apt-get install docker-ce docker-ce-cli containerd.io
vagrant$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
vagrant$ sudo chmod +x /usr/local/bin/docker-compose
# Allow "jenkins" user to run docker commands.
vagrant$ sudo usermod -aG docker jenkins
vagrant$ sudo su -l jenkins
jenkins$ docker ps # This command should work now
jenkins$ ssh-keygen -t rsa -b 4096 -C "your@email.com"
jenkins$ eval "$(ssh-agent -s)"
jenkins$ ssh-add ~/.ssh/id_rsa
jenkins$ cat ~/.ssh/id_rsa.pub # Add this to GitHub
jenkins$ ssh -T git@github.com # Run this after step above
Apply steps defined under "Jenkins > Credentials" section here.
Follow the steps defined here - starting from "Prepare Github repository" section.
Follow the steps defined here - starting from "Prepare Github repository" section.
jenkins$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: inanzzz
Password:
WARNING! Your password will be stored unencrypted in /var/lib/jenkins/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
First of all manually run pipeline for each items in Jenkins so that you know it works.