11/05/2019 - ANSIBLE, DOCKER, JENKINS
In this example we are going to deploy a Dockerised application with Ansible to staging server as part of Jenkins CI/CD pipeline. Read below for the actual flow.
Make sure you covered points below.
ansible
commands.jenkins
user can push images.We have a Jenkins and a Staging servers with details below.
192.168.99.40/jenkins
(IP/user).192.168.99.30/vagrant
(IP/user).The Jenkins and GitHub integration is already set up so when I merge a PR to develop
branch, GitHub communicates with Jenkins where deployment pipeline runs.
secure-delete
package..
├── cicd
│ ├── merge
│ │ └── develop
│ │ └── Jenkinsfile
│ └── provision
│ └── stag
│ ├── hosts.yml
│ └── site.yml
├── docker
│ └── stag
│ ├── docker-compose.yml
│ ├── Makefile
│ └── php
│ └── Dockerfile
├── .dockerignore
├── .env
└── 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('Push') {
steps {
echo '> Pushing docker images to DockerHub ...'
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 ...'
sh 'ansible-playbook cicd/provision/stag/site.yml -i cicd/provision/stag/hosts.yml'
}
}
}
}
all:
hosts:
staging:
ansible_connection: ssh
ansible_user: vagrant
ansible_host: 192.168.99.30
ansible_port: 22
I manually installed docker and docker-compose onto the staging server but ideally it should be done here. Also this file is open for improvements such as making use of variables so on.
---
# All tasks below are run in "staging" server.
- name: Deploy the application to the "staging" server
hosts: staging
remote_user: vagrant
become: yes
tasks:
- name: Create the application directory
file:
path: /home/vagrant/mini
state: directory
owner: vagrant
group: vagrant
- name: Copy docker files over
copy:
src: ../../../docker/stag/
dest: /home/vagrant/mini/docker/stag
owner: vagrant
group: vagrant
- name: Bring the application up
make:
chdir: /home/vagrant/mini/docker/stag
target: run
- name: Install "secure-delete" package
apt:
name: secure-delete
state: present
- name: Secure deleting application files
command: srm -vzr /home/vagrant/mini
We are copying the application files into the image so the files won't be exposed to host OS after build process.
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
Our image is already on the DockerHub.
version: "3"
services:
mini_php:
build:
context: "../.."
dockerfile: "docker/stag/php/Dockerfile"
image: "inanzzz/mini_php:latest"
env_file:
- "../../.env"
build:
@docker-compose build --no-cache
pull:
@docker-compose pull
push:
@docker-compose push
up:
@docker-compose up -d
destroy:
@docker system prune --force --filter 'until=2h'
@docker volume prune --force
run:
@make -s pull up destroy
echo 'success';
echo file_get_contents('./.env');
print_r($_SERVER);
echo getenv('DB_USER').PHP_EOL;
echo getenv('DB_PASS');
.git/
.idea/
.DS_Store/
.gitignore
.dockerignore
readme.md
docker/
cicd/
DB_USER=root
DB_PASS=password
Assume that we have merged a PR info develop
branch.
Running on Jenkins in /var/lib/jenkins/workspace/mini-merge-develop
[Pipeline] Start of Pipeline
> Checking out the Git version control ...
using GIT_SSH to set credentials
Checking out Revision 11d8e7e0a0584ue4112d4b37ee2f0a2df18abar5 (origin/develop)
> Building the docker images ...
+ make -sC docker/stag build
Successfully built cefb05a3fe90
Successfully tagged inanzzz/mini_php:latest
> Pushing docker images to DockerHub ...
+ make -sC docker/stag push
Pushing mini_php (inanzzz/mini_php:latest)...
> Destroying the docker artefacts ...
+ make -sC docker/stag destroy
Total reclaimed space: 0B
> Deploying the application ...
+ ansible-playbook cicd/provision/stag/site.yml -i cicd/provision/stag/hosts.yml
PLAY [Deploy the application to the "staging" server] **************************
TASK [Gathering Facts] *********************************************************
ok: [staging]
TASK [Create the application directory] ****************************************
changed: [staging]
TASK [Copy docker files over] **************************************************
changed: [staging]
TASK [Bring the application up] ************************************************
changed: [staging]
TASK [Install "secure-delete" package] *****************************************
ok: [staging]
TASK [Secure deleting application files] ***************************************
changed: [staging]
PLAY RECAP *********************************************************************
staging : ok=6 changed=4 unreachable=0 failed=0
[Pipeline] End of Pipeline
Finished: SUCCESS
As you can see the /home/vagrant/mini
we created at the beginning has been deleted at the end of the deployment process.
vagrant@staging:~$ ls -l
total 0
Let's check docker components.
vagrant@staging:~$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
inanzzz/mini_php latest 3ec65935d03d 6 minutes ago 14.8MB
alpine 3.9 cdf98d1859c1 4 weeks ago 5.53MB
vagrant@staging:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
99ba5891cee3 inanzzz/mini_php:latest "/bin/sh -c 'tail -f…" 7 minutes ago Up 7 minutes stag_mini_php_1
vagrant@staging:~$ docker exec -it stag_mini_php_1 php src/test.php
success
DB_USER=root
DB_PASS=password
Array
(
[HOSTNAME] => e95350a993d9
[SHLVL] => 1
[HOME] => /root
[TERM] => xterm
[PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[DB_PASS] => 123123
[PWD] => /app
[DB_USER] => inanzzz
[PHP_SELF] => src/test.php
[SCRIPT_NAME] => src/test.php
[SCRIPT_FILENAME] => src/test.php
[PATH_TRANSLATED] => src/test.php
[DOCUMENT_ROOT] =>
[REQUEST_TIME_FLOAT] => 1557934232.1256
[REQUEST_TIME] => 1557934232
[argv] => Array
(
[0] => src/test.php
)
[argc] => 1
)
root
password