Bu örnekte, Dockerli bir uygulama ile çalışmak için Jenkins ile birlikte tam bir CI/CD (Sürekli Entegrasyon/Sürekli Teslimat) pipeline hattı oluşturacağız. Kullanacağımız Jenkinsfile, Makefile komutlarına bağlı olacaktır. Pipeline hattı aşamaları için aşağıya bakınız.


Pipeline


PR builder


Bu pipeline GitHub'da yeni bir feature/* branch yaratıldığında veya push feature/* işlemi oluşduğunda çalışır.


> Build > Test > Destroy

  1. Build: Docker containerlerini yaratır.

  2. Test: Uygulama testlerini çalıştırır.

  3. Destroy: Docker artıklarını siler.

Develop branch merger


Bu pipeline origin/develop branch içine herhangi bir branch eklendiğinde (merge) çalışır. Bu pipeline sadece Staging ortamına teslimat işlemi yapar. Eğer branch origin/master olsaydı teslimat Production ortamına yapılırdı.


> Build > Test > Push > Destroy > Deploy

  1. Build: Docker imajlarını yaratır.

  2. Test: Docker container testini yapar.

  3. Push: Docker imajlarını DockerHub'a iletir.

  4. Destroy: Docker artıklarını siler.

  5. Deploy: Uygulamanın docker imajlarını iletir. Not: Bu adımı bu yazıya eklemeyeceğim çünkü kendi başına uzun bir yazı olur ama konuya daha sonradan ileriki yazılarda değineceğim.

Not: Uygulamanın docker imajını oluşturduğumuzda, sadece gerekli olan klasör ve dosyalar göz önüne alınarak uygulama kodu imaja eklenir. Tek amaç imajı mümkün olduğunca küçük tutmaktır. Gereksiz olan klasör ve dosyalar .dockerignore göz ardı edilir.


Uygulama yapısı


.
├── 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

Dosyalar


cicd/merge/develop/Jenkinsfile


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 ...'
}
}
}
}

cicd/push/feature/Jenkinsfile


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'
}
}
}
}

docker/dev/php/Dockerfile


FROM alpine:3.9

RUN apk add --no-cache php7

WORKDIR /app

RUN rm -rf /var/cache/apk/*

CMD tail -f /dev/null

docker/dev/docker-compose.yml


version: "3"

services:
mini_php:
build:
context: "php"
hostname: "mini-php"
volumes:
- "../../:/app:consistent"

docker/dev/Makefile


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

docker/stag/php/Dockerfile


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

docker/stag/docker-compose.yml


version: "3"

services:
mini_php:
build:
context: "../.."
dockerfile: "docker/stag/php/Dockerfile"
image: "inanzzz/mini_php:latest"

docker/stag/Makefile


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

src/test.php


<?php
echo 'success';

.dockerignore


.git/
.idea/
.DS_Store/
.gitignore
.dockerignore
readme.md
composer.json
composer.lock
docker/

.gitignore


.idea/
.DS_Store/

Kurulum


Aşağıdaki komutlar Jenkins sunucusunda çalıştırılır.


Docker kurulumu


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

Docker compose kurulumu


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

Jenkins kullanıcı hakları


# 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

GitHub SSH bağlantısı


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

Jenkins GitHub anahtarları


Buradaki "Jenkins > Kimlik bilgileri" bölümündeki adımları uygulayın.


PR builder GitHub repository ayarları


"Github repository ayarı" bölümünden başlayarak buradaki adımları uygulayın.


Develop branch merger GitHub repository ayarları


"Github repository ayarı" bölümünden başlayarak buradaki adımları uygulayın.


Docker login


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

Testler


Her şeyden önce, Jenkins'teki her öğeyi elle çalıştırın ve böylece ayarların çalışıp çalışmadığından emin olun.