Jenkins Notlarım
Jenkins Nedir?
Jenkins, kısaca tanımlanacak olursa herhangi bir yazılım projesi kapsamında dinamik olarak gerekli görülen yapısal işlemlerin otomatize edilerek projenin daha hızlı ve kolay biçimde çalışmasını sağlayan bir yapıdır. Aynı zamanda hata raporlamasının gerçekleştirildiği ve kolay tespit hatalarının da sağlanması için fazlasıyla kullanılan bir araçtır.
Sürekli Entegrasyon yöntemi için kullanılmakta olan Jenkins, Java ile yazılmış olan açık kaynak kodlu bir otomasyon sunucusu olarak da bilinir. Yazılım geliştirme süreçlerinin otomatize edilmesi için gerekli olan Jenkins, belirli bir port ve sunucu üzerinde çalışmaktadır. Belirli olan kaynak üzerinden projeye ulaşır ve ardından istenen, belirli işlemleri gerçekleştirmeye başlar. Elde edilen sonuçlar ise belirli kişilere iletilir. Jenkins sayesinde proje sürekli test edilir ve hatalar anında tespit edilerek projenin daha hızlı ve sistemli çalışmasına katkı sağlanır. Manuel olarak gerçekleştirilen build, deploy ve test gibi işlemleri uygulayan Jenkins, süreç dahilinde yaşanabilecek tüm aksaklık ve iletişim eksikliğini de en aza indirger.
Örnek verilecek olursa, Jenkins yazılım geliştirme süreç aşamasında belirlenen kaynak üzerinden projeye ulaşır. Belirli şartlar altında projenin derlenmesini gerçekleştirir. Derlemenin başarılı olmasıyla birlikte testler çalıştırılır. Bu bahsedilen 2 aşamada herhangi bir sorunla karşılaşılmadığı sürece 3. aşamada, deploy aşamasında işlem gerçekleştirilir. Sürekli Teslimat işlemi olarak nitelendirilen bir durumdur. Sürekli teslimatta amaç projenin sürekli çalışır ve güncel halini yansıtmaktır.
Jenkins, build ya da test aşamasında herhangi bir hata ile karşılaşırsa deploy işlemi süreç içerisinde gerçekleştirilmez, bu noktada geliştirici bilgilendirilmek zorunda kalır. Süreç sürekli kendini tekrar eder. Ayrıca Jenkins, bunların yanı sıra statik analiz, dağıtım ve versiyon kontrol sistemi gibi birçok geliştirme sürecinin entegre edilmesini de gerçekleştirir.
Jenkins Kavramları
Yazılım geliştiriciler yazılım projelerinin daha otomatize olması ve neticesinde daha sistemli çalışması için tercih ettikleri Jenkins aracını kullanırken belirli terimlerle karşılaşabilir. Buna göre yazılım sistemlerinde kullanılan Jenkins aracında en çok kullanılan terimleri sizler için derledik. Bu terimler;
- Job: Jenkins projesidir. Otomatize edilmek istenen işler bu kısımda belirlenir. Örnek olarak job config üzerinden şu repository’i çek, bu şartlarda build et, belirlenen kişilere mail ay ve şu testleri çalıştır gibi işlemler bu aşamada belirlenir.
- Node: Job’un üzerinde çalıştığı sunucuyu ifade eden yapıdır. Testler başka bir bilgisayarda koşmak istendiğinde node oluşturulur. Bağlantı için gerekli şartlar gerçekleştirildikten sonra ise node’da testler koşulabilir.
- Plugin(Eklenti): Saf haliyle yüklenen Jenkins ihtiyaca göre plugin yükler ve bu yüklenen pluginler kullanılır. Örnek olarak Job çalıştırıldıktan sonra mail atılması için “Email Etension” eklentisinin yüklenmesi ve post-build adımında kullanılması gerekmektedir.
- Pipeline: Bu terim ile birlikte işlerin ardışık ve sıralı biçimde gerçekleştirilmesi amaçlanır. Bir işlem çıktısının sonraki işlemin girdisi olması anlamına gelmektedir. Örnek olarak ise bir test adımının başarısız olması durumunda diğer test adımının başlamaması verilebilir.
- Jenkinsfile: Jenkins job veya pipeline’ların declarative olarak hangi işlemleri yapacağının belirtildiği dosyadır.
Jenkins Kurulumu -Debian-
Jenkins java tabanlı bir uygulama olduğu için öncelikle java kurulumu yapılır.
sudo apt-get install default-jdk
Jenkins repository sunucuya eklenir ve kurulum yapılır.
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > \
/etc/apt/sources.list.d/jenkins.list'sudo apt-get updatesudo apt-get install jenkins
Jenkins uygulaması başlatırlır.
sudo systemctl daemon-reloadsudo systemctl enable jenkinssudo systemctl start jenkins
Kurulum başarılı şekilde tamamlandıktan sonra http://IP:8080 ile giriş yapılır.
Jenkins uygulamasını unlock etmek için ekranda aşağıdaki komutun çıktısı kullanılır ve Install suggested plugins seçeneği seçilerek devam edilir.
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
Daha sonra jenkins uygulaması için admin kullanıcısı oluşturulur.
Jenkins proxy kurulumu(Nginx)
Jenkins uygulaması default olarak 8080 portu üzerinde çalışıyor. Bunu 80 portunda çalıştırmak için nginx ile proxy işlemi yapacağız. Nginx uygulamasını kuruyoruz.
apt-get install nginx
“/etc/nginx/sites-available/default” içerisine aşağıdaki konfigürasyonu ekliyoruz.
upstream jenkins {
keepalive 32; # keepalive connections
server 127.0.0.1:8080; # jenkins ip and port
}
# Required for Jenkins websocket agents
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80; # Listen on port 80 for IPv4 requests
server_name jenkins.example.com; # replace 'jenkins.example.com' with your server domain name
# this is the jenkins web root directory
# (mentioned in the /etc/default/jenkins file)
root /var/run/jenkins/war/;
access_log /var/log/nginx/jenkins/access.log;
error_log /var/log/nginx/jenkins/error.log;
# pass through headers from Jenkins that Nginx considers invalid
ignore_invalid_headers off;
location ~ "^/static/[0-9a-fA-F]{8}\/(.*)$" {
# rewrite all static files into requests to the root
# E.g /static/12345678/css/something.css will become /css/something.css
rewrite "^/static/[0-9a-fA-F]{8}\/(.*)" /$1 last;
}
location /userContent {
# have nginx handle all the static requests to userContent folder
# note : This is the $JENKINS_HOME dir
root /var/lib/jenkins/;
if (!-f $request_filename){
# this file does not exist, might be a directory or a /**view** url
rewrite (.*) /$1 last;
break;
}
sendfile on;
}
location / {
sendfile off;
proxy_pass http://jenkins;
proxy_redirect default;
proxy_http_version 1.1;
# Required for Jenkins websocket agents
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_max_temp_file_size 0;
#this is the maximum upload size
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffering off;
proxy_request_buffering off; # Required for HTTP CLI commands
proxy_set_header Connection ""; # Clear for keepalive
}
}
Nginx uygulamasını başlatıyoruz.
sudo systemctl daemon-reloadsudo systemctl enable nginxsudo systemctl start nginx
Artık 8080 portunu yazmadan jenkins uygulamasına erişebiliriz.
Jenkins kurulumu tamamlandı. Şimdi ufak bir test job oluşturarak jenkins’in düzgün çalışıp çalışmadığı kontrol edelim. Jenkins ekranına giriş yaptıktan sonra New Item sekmesine tıklanır test amaçlı freestyle job oluşturulur.
General sekmesinde altta bulunan Add build step kısmında Execute shell seçilir. Test amaçlı java -version komutu çalıştırılması istenir ve save edilir.
Job ana ekranında Build Now ile job çalıştırılır. Build history’de en son build numarasına tıklanır ve job detayları kontrol edilir.
Jenkins ortamımız kuruldu ve basit olarak test edildi. Daha detaylı öğrenmeye devam edebiliriz.
Gitlab Jenkins Entegrasyonu
Jenkins default kurulumunda github için gerekli eklentileri barındırır. Gitlab bağlantısı için öncelikle gitlab için gerekli eklentileri kurmamız gerekiyor.
Kurulum işlemi için Manage Jenkins → Manage Plugins yolu izlenir aşağıdaki pluginler yüklenir.
Jenkins’in gitlab api adreslerini kullanabilmesi için token oluşturmamız gerekiyor. Öncelikle Gitlab uygulamamızda jenkins adında admin yetkilerine sahip bir kullanıcı açılır. Oluşturulan kullanıcıya giriş yapılır Edit profile → Access Token ekranından api yetkilerine sahip token oluşturulur.
Token bilgilerini Jenkins ortamına eklemek için Manage Jenkins -> Configure System yolu izlenir ve gitlab kısmına gerekli bilgiler doldurulur.
Token bilgilerini eklemek için Credentials alanında Add butonuna tıklanarak yeni bilgiler eklenir.
Token bilgilerinden sonra Advanced butonuna tıklanır Ignore SSL Certificate Errors seçeneği aktif edilir ve Test Connection butonu ile test işlemi gerçekleştirilir.
Konfigürasyon başarılı şekilde tamamlandığına göre test amaçlı bir pipeline oluşturabiliriz. Öncelikle New Item sekmesinden proje oluştuşturulur.
Pipeline adımında gerekli bilgiler doldurulur ve projeye bağlantı sağlayacak kullanıcı eklenir.
Gerekli alanlar doldurulduktan sonra Credentials seçilir ve pipeline kaydedilir.
Not : git repository eklerken “server certificate verification failed.” hatası alırsanız git sunucusunun sertifikasını jenkins sunucusuna eklemeniz gerekmektedir.
cat git.crt | sudo tee -a /etc/ssl/certs/ca-certificates.crt
Yaptığımız konfigürasyonu test etmek için gitlab’daki projenizin ana dizinine Jenkinsfile dosyası oluşturulur aşağıdaki declarative komutlar yazılır.(Jenkinsfile oluşturma kısmını makalenin devamında detaylı olarak anlatacağım.)
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Build Ediyorum..'
}
}
stage('Test') {
steps {
echo 'Test Ediyorum..'
}
}
stage('Deploy') {
steps {
echo 'Deploy Ediyorum....'
}
}
}
}
Pipeline’ı build ediyorum ve sonuç olarak her şey yolunda görünüyor. Pipeline başarılı şekilde çalıştı.
Kurulum ve testlerimiz bittiğine göre jenkins’i daha iyi anlamak ve pratik yapmak için basitten daha karmaşığa doğru senaryolar üretip bunları jenkins ile çözümleyelim.
Senaryo 1
test.arif.com sitesinde php ile yazılmış bir projemiz var. Bu projenin kodları gitlab üzerinde tutuluyor. Biz siteyi güncellemek istediğimizde aşağıdaki 3 adımı takip ediyorum.
- test.arif.com adresindeki eski dosyalar silinir.
- Güncel git dosyaları test.arif.com sunucusuna kopyalanır.
- Web sunucusu restart edilir.
Yukarıdaki adımları jenkins uygulamasına yaptıracak olursak 2 farklı yaklaşım ile bunu halledebiliriz.
Senaryo 1.0 Çözüm 1
Senaryomuzda dosya taşıma işlemi olduğu için SSH kullanacağız. İlk olarak benim tercihim jenkins üzerinde Execute shell kullanmak olacak. Dosya taşıma ve arif.test.com sunucusunda bazı ayarları yapmak için SSH protokolünü kullanacağız. Bu nedenle jenkins ile sunucu arasında ssh key tanımlarını yapmamız gerekiyor.
jenkins sunucusundaki root kullanıcısında ssh key oluşturulur.
ssh-keygen -t rsa -b 4096 -m PEM
id_rsa.pub içeriği kopyalanır ve arif.test.com sunucusunda bulunan root kullanıcısının /root/.ssh/authorized_keys içerisine eklenir.( Apache uygulaması restart edeceğim için root kullandım. Siz farklı bir kullanıcı kullanabilirsiniz.) Aşağıdaki işlemlerle id_rsa dosyası jenkins tarafından okunabilir duruma getirilir.
cp /root/.ssh/id_rsa /var/lib/jenkinschown jenkins:jenkins /var/lib/jenkins/id_rsa
SSH konfigürasyonu tamamlandıktan sonra Jenkins Dashboard’dan New Item sekmesinden freestyle proje oluştuşturulur.
General ekranında Jenkins Gitlab Entegrasyonu bölümünde ayarladığımız GitLab Connection seçilir.
Source Code Management adımında git seçilir, proje ve daha önce oluşturduğumuz Gitlab Credentials seçilir.
Build adımında Execute shell seçilir ve aşağıdaki kod parçası eklenir ve Save edilir.(Hedef dizinleri kendi ortamınıza göre değiştirebilirsiniz.)
#!/usr/bin/env bashset -e
function execute_ssh() {
ssh -i /var/lib/jenkins/.ssh/id_rsa -o StrictHostKeyChecking=no root@test.arif.com "$@";
}
# Specifing date & time for the delivery
BUILD_DATE=$(date +"%Y%m%d_%H%M")
# Create tar.gz archive with project
tar -czvf arif.tar.gz *
# Create directory for all builds
execute_ssh mkdir -p /opt/arif/
# Copying the project to the DEV server
scp -i /var/lib/jenkins/.ssh/id_rsa -o StrictHostKeyChecking=no arif.tar.gz root@test.arif.com:/opt/arif
# Creating directory and unpack our project
execute_ssh mkdir -p /opt/arif/$BUILD_DATE
execute_ssh tar -xvf /opt/arif/arif.tar.gz -C /opt/devpaytr/$BUILD_DATE
execute_ssh rm /opt/arif/arif.tar.gz
# Restarting Apache2
execute_ssh "systemctl restart apache2";
Sonuç başarılı.
Senaryo 1.0 Çözüm 2
Evet Execute shell bizi sonuca ulaştırdı ama pratik yapmak için Jenkins’de bulunan Publish over SSH eklentisi kullanılabilir. Bu yöntem için öncelikle Manage Jenkins → Manage Plugins yolu izlenir ve Publish over SSH eklentisi kurulur.
jenkins sunucusundaki root kullanıcısında ssh key oluşturulur.
ssh-keygen -t rsa -b 4096 -m PEM
id_rsa.pub içeriği kopyalanır ve arif.test.com sunucusunda bulunan root kullanıcısının /root/.ssh/authorized_keys içerisine eklenir.( Apache uygulaması restart edeceğim için root kullandım. Siz farklı bir kullanıcı kullanabilirsiniz.) Jenkins sunucusunda bulunan /root/.ssh/id_rsa dosyasının içeriği kopyalanır. Daha sonra Manage Jenkins → Configure System ekranında SSH server eklenir.
Name ve hostname gibi alanlar doldurulur Advanced butonuna tıklanır kopyalanan key eklenir.
SSH server ekleme artık tamamlandı. Jenkins Dashboard’dan New Item sekmesinden freestyle proje oluştuşturulur.
General ekranında Jenkins Gitlab Entegrasyonu bölümünde ayarladığımız GitLab Connection seçilir.
Source Code Management adımında git seçilir, proje ve daha önce oluşturduğumuz Gitlab Credentials seçilir.
Build adımında Send files or execute over SSH seçilir.
Name kısmında tanımladığımız SSH server seçilir. Remote directory kısmında ise projenin kopyalanacağı dizin belirtilir.
Sonuç başarılı.
Senaryo 1.1
Senaryo 1'de dosyaları jenkins ile web sunucusu altına atıp, web sunucusunun servisini restart etmiştik. Peki biz dosyayı kopyaladık, hatadan veya başka bir sebepten dolayı bu işlemi geriye almak istersek nasıl yaparız. Bunun çözümü için birçok yöntem vardır ama ben gitlab üzerinde branch ile işlem yapacağım. Elimdeki proje için 2 tane branch oluşturuyorum. Bunlar master ve v1.0
Not: Senaryo 1'in devamı olduğu için çözüm konusu devam niteliğinde olacaktır.
Senaryo 1.1 Çözüm 1
Jenkins’den Gitlab üzerindeki brach bilgilerini parametre olarak kullanmak için Git Parameter Plug-In eklentisi kullanılabilir. Bu yöntem için öncelikle Manage Jenkins → Manage Plugins yolu izlenir ve Git Parameter Plug-In eklentisi kurulur.
Proje içerisine girilir This project is parameterized seçeneği işaretlenir ve Add Parameter alanından Git Parameter eklenir. Aşağıdaki gibi alanlar doldurulur.
Jenkins’in source bilgilerinde gitlab üzerindeki tag bilgilerini kullanabilmesi için Source Code Management alanında ekran görüntüsündeki gibi değişikler yapılır ve kaydedilir.
Sonuç başarılı.
Senaryo 1.2
Git üzerindeki kodları hedef sunucuya atıp işlemler yapıyor, problem durumunda rollback yapabiliyoruz buraya kadar her şey yolunda. Peki yazılımcı arkadaşlar projeyi her güncellediğinde biz bunu el ile mi çalıştıracağız.Tabi ki de hayır.
Senaryo 1.2 Çözüm 1
Bu işlemler için webhook trigger kullanacağız. Trigger yazılımcı projede değişiklik yaptığı zaman arif.test.com adresinin güncellenmesini sağlayacak.
Öncelikle update işleminde jenkins’in tetiklenmesi için Webhook tanımlanması gerekmektedir. Proje içerisindeki trigger bölümünde Build when a change is pushed to GitLab. GitLab webhook URL seçeneği işaretlenir. Belirtilen alan push işlemi sırasında comment olarak yazılarak jenkins’in tetiklenmesini sağlayan kelimedir istediğiniz gibi değiştirebilirsiniz.
Secret Token alanında Generate butonuna tıklanarak token oluşturulur. Bu token gitlab’da proje içerine eklenecektir.
Gitlab’da proje içerisine girilir. Settings →Webhooks yolu izlenir. Aşağıdaki gibi alanlar doldurulur ve kaydedilir.
Bu yapılan değişikliği test etmek için proje içerisinde push işlemi yapılır ve comment olarak jenkins yazılır, bu işlem otomatik olarak jenkins’i tetikleyecek ve projeyi çalıştıracaktır.
Senaryo 2
Jenkins üzerinde birden fazla proje oluşturduk, bazı projeler için bazı kişilere yetki vermemiz gerekiyor. Her kullanıcı kendi projesine ait jenkins projesinde yetkili olması için ne yapabiliriz?
Senaryo 2 Çözüm 1
Yukarıda daha önce yüklediğimiz şekilde Matrix Authorization Strategy eklentisi yüklenir, daha sonra Manage Jenkins → Configure Global Security altında bulunan Authorization bölümünde Project-based Matrix Authorization Strategy işaretlenir ve kullanıcılar için yetkilendirme yapılır.
Yetkilendirme yapmak istediğiniz proje içerisinde Enable project-based security seçeneği işaretlenir ve kullanıcıların bu proje için hangi işlemleri yapacağı seçilir.
Ve sonuç başarılı.