SlideShare a Scribd company logo
1 of 153
JENKINS 2
CemT
En Basit Haliyle Nasıl Çalışır?
Jenkins’in Etkileşimleri
Master & Slave Yapısı
Sürekli D/T/I
(Continuous X)
Süreçleri
Continuous Delivery - Sürekli Teslimat
"Continuous Delivery doesn't mean every change is deployed to production ASAP.
It means every change is proven to be deployable at any time."
Carl Caum from the Puppet Blog
"Continuous Delivery means a team can deploy a feature whenever a product
owner approves the feature and wants to deploy it."
To be able to tell your product owner they can do this, does take time for the
team to institute the right practices to enable CD*.
Sürekli Teslimat, deploy etmek zorunda olmadığın ama her zaman buna hazır
olabildiğin andır.
Continuous Delivery
Continus Delivery aşağıdaki üç disiplinin kombinasyonu
demektir
- Continuous Integration
- Continuous Testing
- Continuous Deployment (istendiğinde)
Bu sürece konfigurasyon yönetimi de gelecek.
Continuous Delivery
Hedefler
Kullanıcıya çalışan yazılımı
olabildiğince hızlı verebilmek
Sıklıkla otomatize edilmiş sürümler
sunmak
Faydalar
Düşük risk, stres
Hızlı yatırımın geri dönüşü (ROI)
İş ihtiyaçlarına geliştirilmiş yanıt
verebilmek
İyileştirilmiş kalite
Hızlıca hataya düşmek (fail-fast)
Yüksek özgüven
Delivery vs. Deployment
Sırf yazılımcı yazdığı kodun
kullanıldığını görsün diye mutlu
etmek ama geri dönüşü olmayan
sonuçlardan dolayı patronu
endişelendirmek için yapılır*.
Daha çok cloud ortamında
sunucularını hızlıca geri
dönebilen, ortak componenti ve
veritabanları olmayan, işin hatasız
olacağını çok geniş verilerle,
regresyonlarla koşan, business’ın
“tüm sorumluluk bendedir, kesinti
mesinti hepsinin hesabını ben
veriyorum” diyebildiği şirketlerde
kullanılır*.
Continuous Delivery vs. Deployment
Sürekli Teslimat(cDelivery), başarılı olan bir yapıyı (build) bir ortama atmanın bir yoludur.
Burada teslimat ile dağıtım arasında bir nüans vardır.
- Teslimat manual olarak,
- dağıtım ise otomatik olarak yapılır.
Sürekli teslimat düzgün bir şekilde uygulandığında, müşteriler her zaman standartlaştırılmış bir test
sürecinden geçmiş hazır yapıya sahip olacaklardır.
Continus Delivery aşağıdaki üç disiplinin kombinasyonu demektir
- Continuous Integration
- Continuous Testing
- Continuous Deployment (istendiğinde)
Bu sürece konfigurasyon yönetimi de gelecek.
Delivery vs Deployment
Delivery ile yapılan sürüm sonuçları geri
alınamayacak ve hassas kararların
verilmesini gerektiren, elle yapılacak
sürümdür.
Deployment ile yapılan sürüm otomatik olduğu
için ya hassas kararların verilmesi gerekmeyen
ya da arkasında ciddi testlerin yapılarak
sonucun sorunsuz olacağına inanıldığı otomatik
yapılan sürümdür.
Continuous Integratıon
Kodu alıp kaynak yönetim sisteminde derleyerek üstünde unit
testleri ve otomatize edilmiş süreçlerden geçirip kodun
sorunsuz olduğunu gördüğümüz süreçtir.
Yazılan kodun, geliştirilen modülün — kısaca geliştirme ortamından çıka gelen bir parçanın — projeye
dahil edilmesi esnasında bir takım süreçlerden geçirilmesine verilen isim. Bağımlılıkların repolardan
indirilmesi, projeye dahil edilmesi, geliştirilen kod parçacığın testlerden (unit, integration, vs…)
geçirilmesi, olası durumlara göre geliştiriciye veya işin sorumlusuna bilgi verilmesi (push notification,
sms, mail, vs…), işin paketlenmesi gibi eylemlerin tamamı, genellikle bu kavramın bir parçası olarak
hayatımızda yer ediyor*.
Sürekli entegrasyon (Continuous Integration = CI), kod üzerinde yapılan her değişikliğin
ardından, tüm sistemin çalışır durumda olduğunu, yapılan değişikliğin sistemin bazı
bölümlerinde kırılmalara yol açmadığını tespit etmek için kullanılan yöntemdir.
Kırılmaları birim testlerle tespit ederiz. Bu testler, yapılan değişikliğin neticesi
olarak yeni bir yapı (build) hazırlandıktan sonra otomatik olarak çalıştırılır.
Yapılan değişiklik yeni yapının bir parçası olduğu için, testlerde oluşan hatalar, yapılan
değişikliğin sistemi kırdığı anlamına gelmektedir. Bu durumdan tüm programcılar haberdar
edilerek, hatanın bir an önce giderilmesi ve testlerin her zaman olumlu sonuç vermesi
sağlanır.
Sürekli entegrasyon ile programcılar tarafından kod üzerinde yapılan çalışmalar
neticesinde her zaman çalışır bir sürümün oluşması sağlanmış olur*.
Özcan Acar - Sürekli Entegrasyon
Özcan Acar - Neden Sürekli Entegre Edilmeli?
Oluşturduğunuz yazılım sistemini sürekli entegre etmiyorsanız, zamanı gelince toptan entegre etmek
zorundasınız. Bunun, neden yazılım hayatınızda karşılaşabileceğiniz en büyük sorun olabileceğini bir örnek
vererek açıklamak istiyorum.
Şimdi şunu hayal edin: Yeni bir otomobilin tasarlanması projesinde yer aldınız. Otomobil tasarlandı ve
otomobili oluşturan parçalar 5 değişik ülkede, 20 değişik firma tarafından üretildi. Bu ülkelerde kullanılan
uzunluk ve ağırlık birimleri (metre, kg vs.) değişik olabilir. Görev dağılımı esnasında yanlış anlamalardan
dolayı üretilen parçalar birbirine uyumlu olmayabilir. Eğer tüm parçalar üretildikten sonra bir çırpıda tüm
otomobili oluşturmak isterseniz, üretim sürecinde meydana gelen hataları daha önceden tespit edemediğiniz
için, yamuk yumuk bir otomobil ortaya çıkacaktır. Ama üretim esnasında koordineli bir şekilde otomobili parça
parça bir araya getirip, parçalar uyuşuyor mu diye kontrol etmiş olsaydınız, meydana gelen uyuşmazlıkları çok
erken tespit ederek, gerekli değişiklikleri yapabilirdiniz. Bu yazılım sektörü için de geçerli. Oluşturulan
sistem komponentleri ne kadar erken entegre edilirse, oluşan uyuşmazlıklar o kadar erken tespit edilir ve
gerekli değişiklikler yapılabilir.
Sürekli entegrasyon çevik süreçlerde çok önemli bir yazılım metodudur. Sistem üzerinde yapılan her değişiklik
sürekli entegrasyonu otomatik olarak gerçekleştiren sunucu tarafından kontrol edilir. Yazılımda kırılmalar
oluşması (compile hataları, eksik sınıflar vs.) durumunda, tüm ekip sürekli entegrasyon sunucusu tarafından
uyarılır. Bu geribildirim sayesinde entegrasyonun ne safhada olduğu anlaşılır.
Continuous Testing
Derlenmiş kodun üstünde entegrasyon, fonksiyonel vb. testlerin geçirildiği ve koda güvenin
sağlandığı süreçtir.
Jenkins Yapısı
Her iş bir diğerini tetikler, Eğer başarısız olan iş olursa tüm süreç başarısız olarak kesilir
Boru Hattı davranışını anlamak için nasıl yürütüldüğü hakkında birkaç noktayı anlamalısınız.
- Adımların (steps) dışında, tüm pipeline mantığı, Groovy koşulları, döngüler, vb. ister basit ister
karmaşık olsun, düğüm (node) bloğunun içinde bile olsa master Jenkins üstünde koşar.
- Adımlar (steps), uygun olan yerlerde iş yapmak için uygulayıcıları (executors) kullanabilirler, ancak her
adım küçük de olsa master’a ek yük yükler.
- Pipeline kodu Groovy olarak yazılır, ancak yürütme modeli derleme zamanında Devam Geçiş Stili'ne
(CPS -Continuation Passing Style-) dönüştürülür.
- Bu dönüşüm, pipeline için değerli güvenlik ve dayanıklılık sağlar, ancak bazı sıkıntılarla birlikte gelir:
- Adımlar (steps) Java kodunu çağırabilir ve Java kodu sayesinde hızlı ve verimli bir şekilde
çalışabilir, ancak Groovy normalden daha yavaş çalışır.
- Groovy çok daha fazla bellek gerektirir, çünkü nesne tabanlı bir sözdizimi bellekte tutulur.
- Boru hatları, master’ın fail olmasından kurtulabilmek için programı ve durumunu kalıcı hale getirir.
Pipeline & Groovy’e Dair Bilinmesi Gerekenler
CI/CD Araçları
Dağıtım Hattının Aşamaları
Compile
&
Unit Tests
Integration
Tests
Source
Code
Analysis
Assembly
&
Packaging
Publish
Artifacts
Commit
Stage
Acceptance
Stage
Promote /
Retrieve
Artifacts
Deploy for
Functional
Testing
Functional
Tests
User
Acceptance
Tests
Deploy To
Production
Jenkins İçinde Kullanılan Teknolojiler
Jenkins Mimarisi
- Jenkins, her yazılım gibi
bir işletim sistemi(host)
üstünde koşar.
- Java application container
veya application server
üstünde koşar (varsayılan
olarak Jetty kullanır)
- Jetty ve jenkinsi başlatma,
durdurma ve izlemek için
harici bir servis
uygulaması çalışır.
- Views ile projeleri(jobs
olarak da bilinir) ve
klasörleri gruplar Jenkins.
- Projeler iş kuyruklarını
(job queue) ve bunları
çalıştıracak executerları
tetikler.
Default Conf. jenkins ile gelir ve herhangi bir build
aşaması için kullanılabilir.
Extra Conf. kullanılan plugin tarafından isteniyor.
Maven Conf. sadece maven projeleri için kullanılır.
Freestyle Conf. herhangi bir proje tipi için
kullanılır. create new jobs ile ilk projemizi
oluştururken freestyle project tipiyle
başlayabiliriz.
Jenkins konteynırının host bilgisayarla bağlı olduğu /var/jenkins_home dizini
C:Userscem.topkayaDocumentsKitematicjenkinsvarjenkins_home olarak ayarlanmış. Projemiz olan ilk project-job olsun ise
host makinede “C:Userscem.topkayaDocumentsKitematicjenkinsvarjenkins_homeworkspaceilk project-job olsun” dizininde
görüntülenecek. Ve doğal olarak içi boş :)
Workspace
Projenin “Build Now”
düğmesine basıldığında sadece
workspace’in silinmesi ayarı
aşağıdaki Console Output
ekranındaki gibi silinecek.
Proje dosyalarının olduğu klasörü yani workspace’i
görebiliyoruz yukarıdaki çıktıda.
“/var/jenkins_home/workspace/ilk project-job olsun”
Proje-Job Yapılandırma Durumları
Scripted
Vs.
Declarative
Scripted Vs. Declarative
Deklaratif ardışık düzen ile Komutlu ardışık düzen arasındaki temel fark, sözdizimleri ve
esneklikleriyle ilgilidir.
Deklaratif pipeline, pipeline’ı kod konsepti olarak destekleyen nispeten yeni bir
özelliktir. Pipeline kodunun okunmasını ve yazılmasını kolaylaştırır. Bu kod Git gibi bir
kaynak kontrol yönetim sistemine kontrol edilebilen bir Jenkinsfile içinde yazılmıştır.
Oysa (Scripted) kodlanmış pipeline, kodu yazmanın geleneksel bir yoludur. Bu satırda
Jenkinsfile Jenkins UI örneğine yazılır.
Bu boru hatlarının her ikisi de Groovy DSL'ye dayanmasına rağmen, scripted pipeline,
Groovy tabanlı daha katı sözdizimleri kullanır çünkü Groovy üzerine inşa edilen ilk
pipeline idi.
Bu Groovy komut dosyası genellikle kullanıcılar tarafından benimsenmediğinden, daha basit
ve daha seçenekli bir Groovy sözdizimi sunmak için deklaratif ardışık düzen eklendi.
Deklaratif (bildirimli) ardışık düzen, "pipeline" etiketli bir blok içinde tanımlanırken,
komut dosyası verilen ardışık düzen, bir "node" içinde tanımlanır.
Scripted
Scripted pipeline, Jenkins pipeline’ı kod
olarak yazmanın geleneksel bir yoludur.
İdeal olarak, Scripted pipeline Jenkins web
arayüzünde Jenkins dosyasında yazılır.
Deklaratif düzenden farklı olarak, scripted
pipeline katı bir sözdizimi kullanır. Bu
nedenle, scripted pipeline kodlanmış
pipeline üzerinde büyük denetim sağlar ve
komut dosyasının akışını kapsamlı bir
şekilde değiştirebilir.
Bu, geliştiricilerin kod olarak ileri ve
karmaşık boru hattı geliştirmelerine
yardımcı olur.
Node, Jenkins mimarisinin, node veya agent
projelerin iş yükünün bir kısmını
çalıştıracağı ve ana düğümün (master node)
işin yapılandırmasını (configuration)
işleyeceği kısmıdır.
Stage bloğu görev ilerledikçe tek bir aşama
veya çoklu olabilir. Ve ortak aşamaları
olabilir.
Kod güdümlü iş oluşturma
Scripted
- Nodes
- Stages
- DSL
- Groovy code
● groovy kodunu kullanabilirsin
● Hata kontrolü ve raporlaması
mevcut
Scripted Vs. Declarative
Declarative
- agent
- [environment]
- [option]
- stages
- stage
- [agent]
- [environment]
- [when]
- [option]
- [input]
- [parameter]
- steps
- DSL
- [post]
- [failure]
- [success]
- [always]
- [cleanup]
● Ön tanımlı kısımlar
● Kod mantığı kullanılamaz
● DSL- yönelimli kontrol ve raporlama mevcut
● Blue-Ocean uyumlu
Parameter
İster önceden ister
Jenkinsfile üstünde
parametreleri tanımlayalım,
projeyi build ettiğimizde
parametreleri görebiliriz.
Input & Parameters & Choice
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Inputlu Aşama') {
input {
message "Devam edelim mi?"
ok "Evet lütfen :)"
submitter "alice,bob"
parameters {
string(name: 'PERSON', defaultValue: 'Mister Rabinsın',
description: 'Selamlarken buradaki değeri kullanacak')
}
}
steps {
echo "Merhaba ${PERSON}, ne güzel sizi görmek."
}
}
}
}
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
parameters {
choice(
choices: ['greeting' , 'silence'],
description: '',
name: 'REQUESTED_ACTION')
}
stages {
stage ('Speak') {
when {
// Only say hello if a "greeting" is requested
expression {
params.REQUESTED_ACTION == 'greeting'
}
}
steps {
echo "Hello, bitwiseman!"
}
}
}
}
/*
* parameters ile okunan değerler strong type okunur
* Yani tip parametrenin tipi Boolean ise okunan değerin
* tipi de Boolean olduğu için toBoolan() ile dönüşüme
* gerek kalmaz.
* evironment (env.<degisken>) ise daima string döner!
*/
Soldaki üç türden, ilk ikisi var
olmayan bir parametre talep
ederseniz null döndürür -
daha sonra yeni bir parametre
eklemeye karar verdiğinizde
ve mevcut tüm projeleri
güncellemek istemediğinizde
çok yardımcı olur!
Ancak üçüncüsü, yapıyı
çökertecektir. (${parm})
INPUT ile Interaktif (etkileşimli) Parametre Tanımlıyoruz
Durdu çünkü input
bekletiyor!
try catch
pipeline {
agent any
triggers {
GenericTrigger(
genericVariables: [
[key: 'service', value: '$.service'],
[key: 'image', value: '$.image']
],
token: env.JENKINS_TOKEN,
causeString: 'Triggered by $image',
printContributedVariables: true,
printPostContent: true
)
}
stages {
stage('Test') {
steps {
script {
try {
echo env.JENKINS_TOKEN
echo service
echo image
} catch (Exception e) {
echo "Using default images: $e.message"
}
}
}
}
}
}
Agent
Agent, tüm boru hattının (pipeline) veya özellikle bir aşamanın (stage)
çalıştığı yerdir. Örneğin, Docker. Agent aşağıdaki parametreleri alır:
● any: tüm pipeline’ın kullanılabilir herhangi bir agent üstünde çalışacağı
anlamına gelir.
● none: blok altındaki tüm aşamaların (stage) ayrı olarak agent ile
bildirilmesi gerektiği anlamına gelir.
● label: sadece Jenkins ortamı için bir etiket
● docker: Docker ortamında pipeline’ı çalıştırmak içindir.
Agent oluşturma başka sayfalarda anlatılacak!
- Groovy temelli
- Süreçlerin adımlarını orkestre eder
- Bir pipeline script gibi job içinde veyaa repository içinde tutulan harici
bir dosya olarak “Jekinsfile” adında saklanabilir
Jenkins Domain Specific Language
Yerel Makinaya
Jenkins Kurulumu
Yerel Makinaya Jenkins Kurulumu
Bu adresten adım adım takip edebilirsiniz.
- Bu adresten war dosyasını indir
- konsoldan şu komutu çalıştır
- java -jar jenkins.war --httpPort=8080
- internet gezgininden http://localhost:8080 adresini aç
jenkins.war çalıştırıldığında $user.home/.jenkins dizinini oluşturmak
ister. Hızlıca çalıştırmak için oluşturduğumuz run.bat dosyası çalışıp
uygulama ayaklandığında %USERPROFILE%.jenkins klasörü oluşur ve
pluginler bu klasöre yüklenir.
Farklı bir dizinde .jenkins klasörünü barındırmak istersek ortam
değişkenlerinden JENKINS_HOME anahtarına istediğimiz yeni dizinin
adresini girip .jenkins dizininin içeriğini taşıyabiliriz.
Jenkins’i Farklı Dizinde Çalıştırmak
Hangi Komut Satırı?
İleride çalıştıracağımız “echo cem” işleminin çıktılarını
sağ tarafta incelediğimizde; jenkins’in docker yansısı
- eğer linux ise, echo işlemini /bin/sh üstünde
çalıştırmakta,
- windows ise cmd üstünde koşturmakta
Host olarak hangi işletim sistemi koşuyorsa buna uygun
command yazmamız veya docker yansısını komutlarımıza göre
seçmemiz gerek.
Linux host üstünde koşan Jenkins için sh ile çalışıyorken
bat ile komutlarımızı çalıştırıyoruz.
Docker İle Jenkins
Kurulumları
Master Agent Node Birinci ve yöneten Jenkins
düğümünün kurulumu
Hangi Docker Yansısı?
Birinci Jenkins düğümü için (eskiden master derdik) jenkins/jenkins yansısını kullanabilirken, ikinci yahut
işçi jenkins ajanları için jenkins/slave yansısını kullabiliriz (slave de yakında kaldırılır).
$ docker pull jenkins/jenkins
Not: jenkins ve jenkinsci/jenkins yansıları kullanımdan kaldırıldı.
$ docker pull jenkins/slave
Docker ile Master Jenkins Kurulumu - 1
Jenkins docker görüntünüzün (image) içinde docker görüntüleri
(images) oluşturmayı planlamıyorsanız, örneğimdeki --privileged
bayrağını göz ardı edebilirsiniz.
Reverse proxy olarak nginx çalıştırmak istersek, nginx
dosyasının default.conf içeriği:
upstream app {
server 127.0.0.1:49001;
}
server {
listen 80;
server_name hosts_a_ne_yazarsan;
location / {
proxy_pass http://app;
}
}
$ docker pull jenkins
$ docker run
--detach
--publish 49001:8080
--volume $PWD/jenkins:/var/jenkins_home
--tty
--privileged
--restart=always
jenkins/jenkins
Docker ile Master Jenkins Kurulumu - 2
Docker ile ister komut satırından ister kitematic ile jenkins/jenkins
isimli docker yansısını yükleyebiliriz.
Kurulum sonrasında docker attach <container-id> ile container konsol
ekranında neler olduğunu görebiliriz.
Komut satırında -d anahtarı olmada çalıştırırsak jenkins ön planda çalışır
ve işletilen komutların çıktılarını yani jenkins processinin I/O
çıktılarını kullandığımız konsol üstünde görebiliriz. Ama -d anahtarını
kullanırsak bu bilgileri görmek için docker attach <container-name>
komutunu çalıştırmamız gerekir.
Slave Agent Node Sonraki Jenkins ajan
düğümlerinin kurulumu
Docker ile Slave Jenkins Kurulumu
docker run
--interactive
--rm
--name agent
--init
-v c:/Temp/Jenkins:/home/jenkins/agent
jenkins/agent
java -jar /usr/share/jenkins/agent.jar -workDir /home/jenkins/agent
Slave Jenkins Ajanı Üstünde İş Çalıştırmak
dpipeline {
agent {
label 'ajan'
}
stages {
stage('Test') {
steps {
sh 'pwd'
}
}
}
}
Jenkins Terminali Root İle Kullanmak
Konteyner ile terminal bağlantısı kurmak istediğimizde --user root argümanı
eklersek root yetkisiyle bash’e bağlanabiliriz. root Kullanıcısıyla apt
işlemlerini yapabilir ve sistem seviyesinde nodejs kurulumu sağlarız. --
privileged Argümanı da root ile bağlanmamızı sağlar.
Not: Resimde gördüğünüz gibi root yetkisi olmadan :/$ ile diğer kullanıcılar için
:/# ile terminale bağlanıyoruz.
- Dolar işareti ($), normal bir kullanıcı olduğunuz anlamına gelir.
- hash (#), sistem yöneticisi (root) olduğunuz anlamına gelir.
- C kabuğunda, komut satırı yüzde işaretiyle (%) biter.
roo@1ee9eb95c6bb:/$ <Kullanıcı Adı>@<makine adı>:<geçerli dizin><[$,#]>
Kullanıcı Adı: Bu örnekte root -veya- jenkins görünür. Oturum açtığınız kullanıcı
hesabını anlarız.
Makine Adı: Makine ana bilgisayar adı. İçinde bulunduğumuz makine adıdır. Docker
için kabın ID değeridir (1ee9eb95c6bb).
Geçerli Çalışma Dizini: Bağlandığımız makinede içinde bulunduğunuz dizini gösterir.
/ : Öne doğru eğik çizgi (/) Kök dizinini işaret eder. “cd /” komutuyla hızlıca kök dizine gidilebilir.
~ : Tilde işareti ana dizin anlamına gelir, yani ilk oturum açarken varsayılan dizin. jenkins kullanıcısı oturum açtığında
“jenkins@d7d9d29b565f:~$” dizinine düşer. Buradaki tilde işareti “/var/jenkins_home” dizinini işaret eder.
Jenkins’in Varsayılan Dilini Değiştirmek
Özetle:
- Locale eklentisini indir
- Jenkins -> Ayarlar/Configuration Kısmında “Varsayılan
Dil” yerine istediğiniz dili kısa koduyla yazın (tr,
en, fr gibi)
- İnternet gezgininizin diliyle görüntülenmemesi için
altındaki “ignore browser preference..” seçilir
Docker ile Master Jenkins Kurulumu - 3
Jenkins’in Şifresi
Kurulum sırasında jenkins ilk giriş için bir şifre
oluşturacak ve bunu konsolumuza yazacak.
jenkins_home Dizinini bağladığınız kendi diskinizdeki
klasörü silerseniz ve jenkins tekrar kurulurken yine
aynı konsolu göreceksiniz.
Eğer burayı kaçırırsanız docker stop <container-name> ile konteynerınızı durdurup başka bir konsol ekranından
docker attach <container-name|id> ile birazdan açacağınız docker container konsolunu takip edebilirsiniz.
Tekrar docker start <container-name> ile başlatırken attach olduğunu konsolda gizli anahtarı görebilirsiniz.
NodeJS
Kurulumu
NodeJs Kurulumu - 1
Konteyner ile terminal bağlantısı kurmak istediğimizde --user root argümanı
eklersek root yetkisiyle bash’e bağlanabiliriz. root Kullanıcısıyla apt
işlemlerini yapabilir ve sistem seviyesinde nodejs kurulumu sağlarız.
Not: Resimde gördüğünüz gibi root yetkisi olmadan :/$ ile diğer türlü :/# ile terminale düşüyoruz.
NodeJs kurulumu için paket listesini güncelleyelim ve sistem
üstünde nodejs kurulumu yapalım ve sonunda node ve npm
versiyonunu görüntüleyelim:
apt-get update 
&& apt-get upgrade -y 
&& curl -sL https://deb.nodesource.com/setup_12.x | bash - 
&& apt-get install -y nodejs 
&& node --version
&& npm --version
Çıktımız:
Jenkins “NodeJS Plugin” eklentisiyle (plugin) nodejs çalıştırabilir. Bu eklentiyle
Nodejs’in farklı sürümlerini araç olarak (tools) kurabilir ve job içinde shell için
PATH’e kaydeder ve npm, node uygulamalarını çalıştırabilirsiniz.
NodeJs Kurulumu -2
Sistemde kurulu bir nodejs
varsa PATH içinde kurulu NodeJS
uygulamasının bin dizini
içindeki “node” uygulamasına
herhangi bir shell içinden
erişilebilir. Bu en genel ve
temiz çözümdür.
Ama sisteme NodeJS kurma
yetkiniz yok ve sadece
Jenkins’i yönetiyorsanız NodeJS
Plugin ile uygun versiyonu
seçerek
/var/jenkins_home/tools/nodejs.
. içinden kullanabilirsiniz.
pipeline {
agent any
// tools’la içeri alıp kullanıyoruz
tools {nodejs "node_14.14.0"}
stages {
stage('Example') {
steps {
sh 'npm config ls'
}
}
}
}
NodeJS İçin Tools Arka Planda Ne Yapar?
NodeJS eklentisi kurulduktan sonra Manage Jenkins > Global Tool
Configuration içinde hangi NodeJS sürümlerini kullanmak istiyorsanız
bir etiketle tanımını yaparsınız. Yandaki örnekte 3 farklı sürüm
için 3 etiket tanımlanmış. Hangisi job içinde kullanılırsa o sürüm
/var/jenkins_home/tools içine indirilir ve shell içinden
erişilebilmesi için geçici PATH içinde tanımlanır. Böylece node veya
npm çağrısı yapıldığında NodeJS uygulamalarına erişilebilinir.
Önce terminal ekranına giriş yapalım:
Paket listesini güncelleyip node kurulumu yapalım ve
unutmayalım setup_8.x deprecate olduğu için yerine 10 veya 12
kurmak daha iyi olacaktır:
Ve son çıktı:
Jenkins Konteyner İçine NodeJS Kurulumu
Docker
Jenkins Slave
Docker Konteyner İçinde Jenkins Slave Çalıştırmak
docker run
-i
--rm
--name agent
--init
jenkins/agent
java -jar /usr/share/jenkins/agent.jar
-i : Keep STDIN open even if not attached
--rm: Docker automatically clean up the container
and remove the file system when the container
exits
--init : konteyner başlatıldığında çalıştırılsın
diye girdiğimiz komutu PID 1 olacak şekilde
başlat. Yani init process olarak başlat.
-v : (Volume Binding) Host makinamızdaki dizinleri
konteynere bağlıyoruz. --rm ile başlattığımız için
konteyner durduğunda içinde yaptığımız her şey
silinecek bu yüzden host makinamızdaki dizinleri
bağlayarak her docker slave başlatıldığında
windows makinamızdaki ssh anahtarları, calisma
dizinleri vs. docker konteynere bağlanacak.
$ docker run
-i --rm
--cpuset-cpus="0-3"
--name agent
-v /c/Users/cem.topkaya/.ssh:/root/.ssh
-v /c/Us../git/calismalar:/home/jenkins/calismalar
-v /c/User..lar/home_jenkins_agent:/home/jenkins/agent
--init
cemkins/agent
Docker Slave Node
Git’i Tanıtalım
whereis git
diyerek konteyner içinde git’in yerini buluruz ve
node üstünde Tool Locations içine git’in dosya
yolunu gireriz, hepsi bu.
1
2
Diskimizi Bağlayalım
1
2
docker run
-i
--rm
--name agent
-v /c/Users/cem.topkaya/git/calismalar:/home/jenkins/calismalar
-v /c/Users/cem.topkaya/git/calismalar/home_jenkins_agent:/home/jenkins/agent
--init
jenkins/agent
java -jar /usr/share/jenkins/agent.jar
3
4
whereis npm
whereis npm
ile node yüklenmediğini görürüz. Sunum dosyasında node kurulumuyla ilgili komutlar
konteynerin konsoluna bağlanarak çalıştırabiliriz. Ancak unutmayalımki node
yüklemesini konteyner içine yapıyoruz ve eğer --rm anahtarıyla başlattığımız
konteyner, görevi bitince kaldırılır ve yeni konteyner başlattığımızda yine node
kurulumu gerekir.
Veya
jenkins/agent yansısını miras alarak içinde node yüklü yeni bir yansı yaratabiliriz.
FROM jenkins/agent
USER root
RUN apt-get update 
&& apt-get upgrade -y 
&& curl -sL https://deb.nodesource.com/setup_12.x | bash - 
&& apt-get install -y nodejs 
&& node --version 
&& npm --version
EXPOSE 22 80
USER jenkins
CMD java -jar "/usr/share/jenkins/agent.jar"
#ENTRYPOINT java -jar "/usr/share/jenkins/agent.jar"
Jenkins Ayarları
Jenkins Admin Kullanıcısı Oluşturmak
İlk ekrana girdiğiniz gizli kelimeden sonra önerilen
pluginleri kurar ve ardından kullanıcı tanımlarsınız. Ve
artık jenkins hizmetinize sizin tayin ettiğiniz (örn. 8080)
porttan başlatılır.
Global Tool
Configuration
JDK
Linux üstünde
$ which javac
ile JDK dizininin
yolunu öğrenebilir ve
Global Tool
Configuration içinde
tanımlayabiliriz.
Git
Linux üstünde $ which git ile GİT dizininin yolunu öğrenebilir ve
Global Tool Configuration içinde tanımlayabiliriz.
NodeJS
Linux üstünde $ which node ile Node dizininin yolunu öğrenebilir ve
Global Tool Configuration içinde tanımlayabiliriz.
GİTHUB
Authentication
Github Authentication
Bilgisayarınızda lokalde çalışan bir jenkins olsun.
Kodlarınızı barındırdığınız git adresini projenizin
Source Code Management sekmesine girdiniz.
Jenkins arka tarafta HEAD metoduyla ilgili adrese bir
istek yapacak.
Eğer kullanıcı bilgileriniz geçerli değilse yandaki
hatayı verecek.
Failed to connect to repository : Command "git.exe ls-remote -h -- https://github.com/cemtopkaya/angular-module.git HEAD" returned status code 128:
stdout:
stderr: Logon failed, use ctrl+c to cancel basic credential prompt.
remote: Invalid username or password.
fatal: Authentication failed for 'https://github.com/cemtopkaya/angular-module.git/'
Bu durumda artık github için bir kullanıcı doğrulama yöntemi seçerek devam etmeliyiz.
- Windows Kimlik Yöneticisinde kullanıcı bilgilerinin depolanması
- Username ve Password ikilisi olan credential
- Github Token kullanmak
Kullanıcı Bilgileri Yöneticisi
Konsol üstünden github reposunun clone ile çekilmesi sağlandığında Windows
Kimlik Bilgileri Yöneticisi kullanıcı bilgilerini depolayacak ve eğer
Credentials açılır kutusundan bir seçim yapılmamışsa, Jenkins her github
için arka planda yapacağı istekte sistemde kayıtlı olan bu bilgileri
kullanacak.
Github için yapılacak istek başarısızsa aşağıdaki gibi, başarılıysa boş
gövdeli cevap döner:
Github Kullanıcı Adı & Şifresi
Sistemde kayıtlı kullanıcı bilgileri yerine belirlediğimiz
credential ile bağlanmak istediğimiz durumdur.
Github reposunu yazdığımız yerde Add düğmesiyle (veya Jenkins
Credential menüsünden) Username with Password tipinde bir
tanımlama yaparız. Kullanıcı adı ve şifresiyle bir credential
oluşturup projenin Source Code Management sekmesinde
Credentials açılır kutusunda seçili hale getirebiliriz.
Github Token ile Webhook
(1) Github üstünden bir Token yaratıp Jenkins içinde
yeni bir Credential olarak tanımlarız. (2) Bu kez
Jenkins’in tüm projeleri tarafından kullanılabilecek
şekilde token bilgisini ayarlayacağız
Manage Jenkins / Configure System / Github
içinde az önce oluşturduğumuz TOKEN seçilerek Github
server ile webhook için kullanılacak token ayarlanır.
Oluşturduğumuz token’ın testi için curl -u
username:token https://api.github.com/user komutunu
konsoldan çalıştırabiliriz.
Github Ayarı
Github üstündeki bir repoya bağlanmak istersek github sunucu
ayarlarına hangi token ile bağlanacağımızı söylememiz gerekiyor.
Sonrasında projemizin General ayarlarında bu projenin bir Github
projesi olduğunu seçmeli ve Source Code Management içinde git
seçeneğini işaretleyip hangi adresten veri çekeceksek projenin bağlı
olduğu github kaynak kodunun adresini ve hangi branch üstünde
koşacağımızı belirtmeliyiz.
Build ettiğimizde kodun indiğini görürüz.
Github Public Repo Ayarı
Projenin (burada ng_form adında freestyle tipinde),
Configure sekmesinden Source Code Management kısmında
Git seçilip, clone yapmak için kullandığımız adresini
yapıştıralım. Projeyi build ettiğimizde kodlar
çekilerek workspace içine dosyalarımız konulacak.
1 2
3
4
5
Github Private Repo Ayarı
Önce kayıtlı şifreyi silelim ki; github üstünde private repomuza
giderken şifre sorulur hale gelsin ve yerelde çalışan jenkins için de
şifre istensin. Böylece Github token yaratma yoluna gidelim.
git config --global credential.helper store ile kullanıcı adı ve
şifresini bilgisayara depolayacağız demiş oluruz. Kullanıcı adı ve
şifresini ilk girdiğimiz anda önce %USERPROFILE.git-credentials
dosyasına https://gitKullaniciAdi:gitSifresi@github.com bilgisi
yazılır ardından Windows Kimlik Bilgileri Yöneticisi bu bilgileri ön
bellekler.
Eğer Windows Kimlik Bilgileri Yöneticisi üstünden siler tekrar git
clone ile yerele kodları çekmek istediğimizde kullanıcı bilgileri
WinKimlikBilgYöneticisi üstünden okunmak istenir, bulunamayınca .git-
credentials dosyasından veriler okunur ve WinKimlikBilgYöneticisi
üstüne tekrar yazılır.
Bir sonraki clone işleminde WinKimlikBilgYöneticisi kullanıcı
bilgilerini servis eder ve .git-credentials dosyasına gerek kalmadan
kullanıcı girişi sağlanmış olur.
Kullanıcı Bilgileri Sırası
1. Windows Kimlik Bilgileri Yöneticisi
2. .git-credential
3. cache
Declrative Pipeline
GİT
Aksiyomları
sh('''
git config user.name 'my-ci-user'
git config user.email 'my-ci-user@users.noreply.github.example.com'
''')
withCredentials([usernamePassword(credentialsId: 'my-credentials-id', usernameVariable: 'GIT_USERNAME', passwordVariable:
'GIT_PASSWORD')]){
sh('''
git config --local credential.helper "!f() { echo username=$GIT_USERNAME; echo password=$GIT_PASSWORD; }; f"
git push origin HEAD:$TARGET_BRANCH
''')
}
stage('Push') {
environment {
GIT_AUTH = credentials('my-predefined-credentials-id')
}
steps {
sh('''
git config --local credential.helper "!f() { echo username=$GIT_AUTH_USR; echo password=$GIT_AUTH_PSW; }; f"
git push origin HEAD:$TARGET_BRANCH
''')
}
}
Push
via
HTTPS
Push
via
HTTPS
git branch: 'dev', credentialsId: 'cred_id_bitbuket_icin', url: 'https://jenkins.kullanici@bitbucket.com/scm/cin/gui_test.git'
git checkout -B $TARGET_BRANCH
Checkout
pipeline {
agent any
stages {
stage("Build") {
steps {
// Create a dummy file in the repo
sh('echo $BUILD_NUMBER > example-$BUILD_NUMBER.md')
}
}
stage("Commit") {
steps {
sh('''
git checkout -B $TARGET_BRANCH
git config user.name 'my-ci-user'
git config user.email 'my-ci-user@users.noreply.github.example.com'
git add . && git commit -am "[Jenkins CI] Add build file"
''')
}
}
stage("Push") {
environment {
GIT_AUTH = credentials('support-team-up')
}
steps {
sh('''
git config --local credential.helper "!f() { echo username=$GIT_AUTH_USR; echo password=$GIT_AUTH_PSW; }; f"
git push origin HEAD:$TARGET_BRANCH
''')
}
}
}
}
pipeline {
agent any
stages {
stage("Tag and Push") {
when { branch 'master' }
environment {
GIT_TAG = "jenkins-$BUILD_NUMBER"
}
steps {
sh('''
git config user.name 'my-ci-user'
git config user.email 'my-ci-user@users.noreply.github.example.com'
git tag -a $GIT_TAG -m "[Jenkins CI] New Tag"
''')
sshagent(['my-ssh-credentials-id']) {
sh("""
#!/usr/bin/env bash
set +x
export GIT_SSH_COMMAND="ssh -oStrictHostKeyChecking=no"
git push origin $GIT_TAG
""")
}
}
}
}
}
Projeleri Sıralı
Tetiklemek
Sıralı Olarak Projeleri Build Etmek
1. Görevi build
ettiğimizde konsol
çıktısında 2.nin sıraya
girdiğini yazar.
Aynı şekilde ana ekranda
“Build Queue” kısmında da
sıradaki görevleri
görebiliriz.
Delivery Pipeline İle Görselleştirme
1
2
3
Agent/Node
Tanımlama
(Slave Jenkins)
Gerekenler
- VirtualBox veya VMware Player kurula
- En hafifinden linux kurulu bir disk indirilip sanal
makine (virtual machine) çalıştırıla
- Sanal makine içine java kurula
- openssh-server linux içine kurulup dışarıdan erişilebilir
hale getirile
- jenkins içinde yeni vm’in bilgileriyle bir node/agent
oluşturula
Sanal Linux Kurulumu
https://www.osboxes.org/linux-lite/
Adresinden linux kurulu disk
indirilerek VirtualBox üstüne
eklenir.
Hemen “passwd” komutuyla
osboxes.org kullanıcısı, “sudo
passwd root” ile root şifresi
değiştirilir.
VirtualBox Ağ Ayarları
VirtualBox üstünde 3 ağ tanımlı. Sanal
makinamızın 1. ağ bağdaştırıcı NAT ile internete
bağlanması için iken 2. ağ bağdaştırıcı host ile
doğrudan bağlantı kurması için.
Not: Farklı ayarlar da yapılabilir
Linux Ağ Ayarları
nmtui kullanıcı arayüzü, dhclient veya ifconfig ile ağ
işlemlerini yapabiliriz
Ağ Ayarlarını Görüntülemek
DHCP Sunucusuna “merhaba” gönderip iletişimi görelim
$ dhclient -v
$ ifconfig -a
Ağ Ayarlarını Tazelemek
$ sudo dhclient -v -r
$ ifconfig ağ_adı down
$ ifdown ağ_adı
$ ifconfig ağ_adı up
$ ifup ağ_adı
Ağ Servisini Yeniden Başlatmak
$ /etc/init.d/nscd restart
Sadece Openjdk’yı kaldırmak istiyorsak:
$ sudo apt-get remove openjdk*
Openjdk’yı tüm bağımlılıklarıyla kaldırmak istiyorsak:
$ sudo apt-get remove --auto-remove openjdk*
Openjdk ve ayar dosyalarını kaldırmak istiyorsak:
$ sudo apt-get purge openjdk*
Openjdk, bağımlılıkları ve ayar dosyalarını kaldırmak
istiyorsak:
$ sudo apt-get purge --auto-remove openjdk*
Java Yüklemek & Kaldırmak
Repoyu güncelleyerek java indirebileceğimiz adresleri
çekeriz:
$ apt-get update
$ apt install oracle-java11-installer
$ apt install default-jre
$ apt install openjdk-11-jre-headless
$ apt install openjdk-8-jre-headless
$ apt install openjdk-8-jdk-headless
Sadece openjdk-8-jdk-headless paketinin kurulması hem
java hem javac için yeterli olacaktır.
Sürüm Kontrolü
java Runtime (JRE) : $ java -version
Java Development Kit (JDK): $ javac -version
Yeni Kullanıcı Tanımlamak
Master olan Jenkins projelerin
tanımlandığı, ayarlarının yapılıp
yapılandırmak için tetiklendiği ve
çıktıların gözlemlendiği ilk
kurulumumuzdur.
Diğer sunucular (node/agent’lar) ise
agent.jar isimli dosyanın sürekli çalışıp
master jenkins tarafından gelen işlerin
yapıldığı düğümlerdir. Bu düğümlere
job’ların yüklenmesi için bir kullanıcı
tanımlanır ve master jenkins, ssh
marifetiyle bağlanarak ilgili agent.jar
dosyasını yükler ve çalıştırır.
agent.jar Dosyası tabiatı gereği Java
kurulumu da gerektirdiği için önceden
yüklenmiş olması gerekir.
Kullanıcı Silmek
Silinmek istenen kullanıcı aktif bir processleri killall ile
durdurulur veya zorla (force) silmek istediğimizi -f argümanı ile
veririz.
$ killall -u kullanıcı_adı
$ userdel -f --remove-home kullanıcı_adı
Yeni Kullanıcı Oluşturmak
$ useradd -m cemkins
Yeni Kullanıcıya Şifre Atamak
cemkins kullanıcısının yeni şifresini iki kez girilir ve yeni
kullanıcıyla sisteme giriş yapılar.
$ passwd cemkins
Yeni Kullanıcı Profilinde Jenkinse Özel Dizin Oluşturmak
Yeni kullanıcının profili /home/kullanıcıAdı dizininde oluşacaktır.
Jenkins bu klasörün altına remote.jar dosyası ve remote dizini
oluşturacağı için derli toplu olsun diye biz jenkinsKokDizini diye
bir klasör oluşturalım.
$ mkdir jenkinsKokDizini
SSH Kurulumu
ssh Server Kurulur
$ sudo apt-get install openssh-server
ssh Servisi Faal Edilir
$ sudo systemctl enable ssh
ssh Servisi Başlatılır
$ sudo systemctl start ssh
Servisin Durumu Kontrol Edilir
$ sudo systemctl status ssh
ssh Bağlantısı Test Edilir
$ ssh root@makina-adı|ip
Dışarıdan Bağlanmak İçin Ayar Yapılandırılır
# ile başlayan satırlar yorum satırı demektir. Bazı komutların yorum
satırı olmadığı belirtmemiz gerekecek:
$ vi /etc/ssh/sshd_config
#PermitRootLogin prohibit-password
satırı aşağıdaki hale getirilir
PermitRootLogin yes
#PasswordAuthentication yes
yorum satırı olmaktan çıkarılır
PasswordAuthentication yes
Eğer ssh key ile giriş yapılabilsin istiyorsak aşağıdaki satırlar
yorum satırı olmaktan çıkarılır
#PubkeyAuthentication yes
#AuthorizedKeysFile .ssh/authorized_keys
ssh Secure Shell anlamıa gelir ve telnetin şifrelenmiş halidir.
sshd ise servis (daemon) halinde çalışan ssh sunucusudur.
sshd_config içinde yapılan değişikliklerin etkili olması için servisin
tekrar başlatılması gerekir.
ssh Sorun Giderme
SSH bağlantısı sırasında “Host key verification
failed.*” hatası alınırsa, bağlantı kurulacak
makina için “bilinen hostlar” dosyasında
güncelleme yapmak için $ ssh-keygen -R
192.168.99.102 komutu çalıştırılır. IP adresi,
bağlantı kurmak istediğiniz uzak makinanın adresi
veya ismidir.
known_hosts dosyası .ssh dizini altındadır.
$ ssh-keygen -R <ip | host_adı>
Komutuyla her uzak bağlantı için bir key üreterek
güvenilir bağlantılar listesine ekler.
SSH servisini otomatik üretiyorduk ve
diyelimki ayarlar dosyası çalışmaz hale
geldi ve aşağıdaki hatayı almaya
başladık:
Unit sshd.service could not be found
Tüm openssh-server’ı kaldırmak yerine
konfigurasyon dosyalarını kaldırıp tekrar
kurulum yapmak yeterli olacaktır.
$ apt-get purge openssh-server
$ apt-get install openssh-server
Elbette tüm ssh server’ın kaldırılıp
tekrar kurulmasında da sakınca yok
$ apt-get remove --purge openssh-server
$ apt-get install openssh-server
$ service ssh restart
$ service ssh status
Docker Jenkins İçin Plug-In Kurulumunda Hata
Docker versiyonu jenkins/jenkins yansısını
kullanıyor ve plugin güncellemesi yapamadığını
görüyorsanız jenkinsin pluginleri indirebileceği
adresi ortam değişkeni olarak jenkins kabınıza
vermeniz gerekiyor.
Bunu 3 farklı adresi verip deneyebilirsiniz:
1. http://ftp-nyc.osuosl.org/pub/jenkins
2. http://mirrors.jenkins-ci.org
3. https://updates.jenkins.io/download/plugins
Kitematik ile veya docker kabınızı çalıştırırken
yapabilirsiniz
docker run --name jenkinscim
....
-e JENKINS_UC_DOWNLOAD 'http://ftp-
nyc.osuosl.org/pub/jenkins' jenkins/jenkins
Agent Launch Sorun Giderme
Slave node üstünde ssh kurulu ancak
java yok!
> Java kurulur ve tekrar denenir.
Checking java version of /home/cemkins/jenkins_kok_dizini/jdk/bin/java
Couldn't figure out the Java version of /home/cemkins/jenkins_kok_dizini/jdk/bin/java
bash: /home/cemkins/jenkins_kok_dizini/jdk/bin/java: No such file or directory
Çalıştırmak istediği komuş aşağıda göreceğiniz üzere remoting.jar dosyasını
ayaklandırarak master üstünden slave ile konuşabileceği bir iletişim kanalı açmak:
[SSH] Starting agent process:
cd "/home/cemkins/jenkins_kok_dizini" && /usr/bin/java -jar remoting.jar -workDir /home/cemkins/jenkins_kok_dizini -
jar-cache /home/cemkins/jenkins_kok_dizini/remoting/jarCache
- Yukarıdan anlayacağınız üzere /usr/bin/java ile çalıştırılabilir java dosyasına erişmek ve -jar argümanı ile
remoting.jar dosyasını ayaklandırmak istediğini söyleyecek.
- remoting.jar dosyasına çalışılacak dizini ve -jar-cache ile ön bellek dizinini vermek istiyor
Java yolunu öğrenmek için $ whereis java konsola yazılır ve uygun dosya yolu bulunur ve Advanced düğmesiyle açılan bölümde
JavaPath etiketli alana java’nın yolu yazılır.
Not: Eğer yüklü değilse java yükleme kısmına bakabilirsiniz.
Agent Tanımlama
Jenkins çeşitli formlarda saklanabilen tüm
credential bilgilerini Credentials menüsünde
saklıyor.
Node tanımında login olacağımız linux
makinasındaki cemkins kullanıcısının bilgilerini
Credentials satırında Add düğmesiyle(1) açılan
ekranda(2) tanımlıyoruz.
SSH yaptığımızda, sunucu makine /etc/ssh içinde
tanımlı kendi HOST KEY’ini gönderir, SSH istemci
makinesi ise known_hosts dosyasında bu anahtarı
bulursa bağlantı kurulur. Bulamazsa uzak makinenin
HOST KEY bilgisini known_hosts dosyasına eklemek
istermiyiz diye sorar. Böylece daha sonraki
bağlantılarda ssh server doğrulanır.
1
3
2
Private Docker
Registry
Private Registry
# docker tag alpine:latest localhost:5000/malpine
# docker push localhost:5000/malpine
The push refers to repository [localhost:5000/malpine]
beee9f30bc1f: Pushed
latest: digest: sha256:cb8a92...b8d221 size: 528
# curl http://localhost:5000/v2/_catalog
{"repositories":["malpine"]}
Private Registry Kurulumu
$ docker run -d -p 5000:5000 --restart always --name registry registry:2
https://docs.docker.com/registry/spec/api/
# curl http://localhost:5000/V2/_catalog
# curl http://localhost:5000/v2/<name>/tags/list
DELETE /v2/<name>/manifests/<reference>
openssh-server
Kurulumu
Sadece openssh-server’ı kaldırmak istiyorsak:
$ sudo apt-get remove openssh*
openssh-server’ı tüm bağımlılıklarıyla kaldırmak
istiyorsak:
$ sudo apt-get remove --auto-remove openssh*
openssh-server ve ayar dosyalarını kaldırmak
istiyorsak:
$ sudo apt-get purge openssh*
openssh-server, bağımlılıkları ve ayar dosyalarını
kaldırmak istiyorsak:
$ sudo apt-get purge --auto-remove openssh*
openssh-server Yüklemek & Kaldırmak
$ apt-get update
$ apt-get install openssh-server
openssh-server Kurulum Detayları
$ apt-get install openssh-server
…
The following additional packages will be installed:
openssh-sftp-server ssh-import-id
Suggested packages:
molly-guard monkeysphere rssh ssh-askpass
The following NEW packages will be installed:
openssh-server openssh-sftp-server ssh-import-id
...Fetched 389 kB ...Unpacking openssh-sftp-server …
Preparing to unpack .../openssh-server_1%3a7.6p1-4ubuntu0.3_amd64.deb ...
...Preparing to unpack .../ssh-import-id_5.7-0ubuntu1.1_all.deb ...
...Creating config file /etc/ssh/sshd_config with new version
...Creating SSH2 RSA key; this may take some time ...
2048 SHA256:Fy/9w38/BzTJCVEdu7czKDg5DcwHSrQT/2/fpTnHufc root@osboxes (RSA)
Creating SSH2 ECDSA key; this may take some time ...
256 SHA256:oZaVFTz0Eh4PtY4pTFkoAjlcjoqb+YJJppDLtQiUtl8 root@osboxes (ECDSA)
Creating SSH2 ED25519 key; this may take some time ...
256 SHA256:TSmPKhMlzRDys5GQSK9mC8fLaRmDEO7dIlLLGdZDPAw root@osboxes...
Created symlink /etc/systemd/system/sshd.service → /lib/systemd/system/ssh.service.
Created symlink /etc/systemd/system/multi-user.target.wants/ssh.service → /lib/systemd/system/ssh.service.
...Processing triggers for systemd (237-3ubuntu10.39) ...
Git’e
SSH Anahtarıyla
Bağlanmak
ssh Anahtarları Oluşturmak ve Kullanıma Açmak
1) SSH Anahatarı Oluşturmak: ssh-keygen komutu
çalıştırıldığında, yeni ssh anahtarının adını soracak.
- Eğer enter ile geçersek $HOME dizini içinde .ssh
klasörünü ve içerisine id_rsa dosyasını gizli anahtarı
(private key), id_rsa.pub dosyasını da public anahtarı
saklayacak şekilde oluşturur.
- Eğer bir dosya adı girersek bu kez $HOME dizini içinde
dosyaAdi adında private, dosyaAdi.pub adında public
anahtarları oluşturur.
- Mesela github’a bağlanmak için bir ssh anahtarı
yaratıyor olalım ve dosya adına github_cemtopkaya
diyelim. Bu durumda $HOME/github_cemtopkaya ve
$HOME/github_cemtopkaya.pub adında private ve
public anahtarları oluşturacak.
Tabi bu dosyaları şifreleyecek ve sadece bizim bileceğimiz bir
passphrase (parola) girmemizi iki kez istedikten sonra dosyalar
oluşturulmuş olacak.
$ ssh-keygen -t rsa -b 4096 -C "cem.topkaya@hotmail.com"
2) SSH Agent’a SSH Anahtarlarını Kaydetmek: ssh-keygen
komutuyla oluşan anahtarları ssh-agent üstüne kaydederek
kullanıma sunmalıyız. Ama önce ssh-agent çalışıyor mu diye
bakalım.
$ eval "$(ssh-agent -s)"
Şimdi ürettiğimiz anahtarları ekleyeceğiz. Örneğin github,
gitlab ve bitbucket için farklı public ve private
anahtarlar üretmiş olalım ve hepsini bir kerede ekleyelim.
$ ssh-add github_cemtopkaya bbCemTopkaya .ssh/id_rsa
$ sudo -su giris_yapilan_kullanici_adi
$ ssh-keygen -t rsa -b 4096 -C "cem.topkaya@hotmail.com"
$ eval "$(ssh-agent -s)"
$ ssh-add github_cemtopkaya bbCemTopkaya .ssh/id_rsa
Github & Jenkins SSH Anahtar Ayarları
Jenkins üstünde Global Credential oluşturuyoruz.
- SSH Username with private key seçeneğiyle
- Username ile bağlanacağımız sistemin kullanıcı adı,
- ID bilgisini biz yazarsak anlamlı ve eşsiz bir tanımlama, boş bırakırsak UUID değer atanır,
- Private Key kısmına bir önceki sayfada hazırladığımız SSH anahtarının private kısmını
yapıştırırız. Böylece Jenkins privte anahtar içeren dosyayı aramak, dosya yoluna bağlı
kalmak zorunda olmayacaktır.
- Passphrase ise ssh-keygen ile SSH anahtarını oluştururken bize gizli bir parola girmemizi
istediğinde yazdığımız metin.
Github üstünden kişisel ayarlardan SSH and GPG keys sekmesinde ise Key kısmına SSH
anahtarımızın public anahtarının içeriğini yapıştırıyoruz ve tanımlama için title alanına ayrıştırılabilir bir
metin girilir.
Git’e
Kullanıcı Adı &
Parolayla
Bağlanmak
Jenkins üstünde
oluşturduğumuz “SSH Username
with private key” türündeki
credential’ı
kullanabileceğimiz GİT SCM
Reposuna SSH ile bağlantı
kurmamız gerekiyor.
Freestyle Projede
https & SSH Git Repo Bağlantısı
Jenkins üstünde oluşturduğumuz “SSH
Username with private key” türündeki
credential’ı kullanabileceğimiz GİT
SCM Reposuna SSH ile bağlantı
kurmamız gerekiyor.
Pipeline Projede
Https & SSH Git Repo Bağlantısı
git(
url: 'ssh://git@bitbucket.org:company/repo.git',
credentialsId: 'xpc',
branch: "${branch}"
)
git branch: params.SOURCE_BRANCH_NAME,
credentialsId: params.GIT_HTTP_CRED_ID,
url: params.GIT_REPO_ADDR_HTTP
checkout([
$class: 'GitSCM',
branches: scm.branches,
doGenerateSubmoduleConfigurations: false,
extensions: scm.extensions + [[
$class: 'SubmoduleOption',
disableSubmodules: false,
recursiveSubmodules: true,
reference: '', trackingSubmodules: false
]],
submoduleCfg: [],
userRemoteConfigs: scm.userRemoteConfigs
])
withCredentials([
usernamePassword(
credentialsId: your_credentials,
passwordVariable: 'GIT_PASSWORD',
usernameVariable: 'GIT_USERNAME')])
{
sh "git tag ${your_tag}"
sh "git push https://${GIT_USERNAME}:${GIT_PASSWORD}@${repo} ${tag}"
}
sshagent ( ['a-jenkins-credential']) {
sh '''
ssh -vv myuser@myserver echo testing connection || true
ssh-add -L
echo done running remote windows test
'''
}
Bitbucket
Projesiyle Jenkins
Job Tetiklemek
http://www.adobe.com.by/pdf/meetup-12/Meetup_12_Mytroshin.pdf
http://www.adobe.com.by/en/#archive1
Linux Mint’e
Jenkins Kurulumu
Linux Mint 19.2C Sürümü
https://sourceforge.net/projects/osboxes/files/v/vb/31-Lx-M-t/19.2/Cinnamon/19-2C-64bit.7z/download
1) Uygulama Havuzunu Güncellemek
$ sudo apt update
2) Snap İle Jenkins Kurmak
$ sudo apt install snapd
3) Snap İle Daha Önce Kurulu Jenkins’i Güncellemek
$ sudo snap refresh jenkins --classic
4) Jenkins Servisinin Durumunu Görmek
$ systemctl status snap.jenkins.jenkins.status
5) Jenkins Servisi Durmuşsa Başlatmak
$ systemctl start snap.jenkins.jenkins.status
6) Jenkins Servisi Çalışıyorsa Browser Üstünde
Görüntülemek
$ xdg-open http://localhost:8080
Bir Browser Aç Adres Satırına Şunu yaz:
http://localhost:8080
7) Git Kurmak
$ sudo apt install git
8) JDK Kurmak
$ sudo apt install openjdk-8-jdk-headless
9) SSH Server (jenkinse ssh ile uzak bağlantı için)
$ sudo apt install openssh-server
Jenkins
$
Jenkins
$
Jenkins
$
Groovy İle
Script Yazmak
Veri Tipleri
● Simple data types
○ Strings
○ Numbers
○ Regular expressions
○ Booleans
○ Arrays
● Collections
○ List
○ Set
○ Maps
○ Ranges
Başlıklar
groovy-net groovy-xml groovy-string groovy-number groovy-html groovy-date groovy-collections
String
Java'da olduğu gibi, karakter verileri çoğunlukla
java.lang.String sınıfı kullanılarak işlenir.
Groovy strings iki çeşittir:
- plain strings,
- GStrings.
Düz dizeler java.lang.String ve GStrings
ise groovy.lang.GString örnekleridir.
GStrings, ifadeleri (genellikle birçok komut
dosyası dilinde dize enterpolasyonu olarak
adlandırılır) çalışma zamanında çözümlenmesine
ve değerlendirilmesine olanak tanır.
Dizeler tek, çift, üçlü tek tırnak veya üçlü çift
tırnak kullanılarak tanımlanabilir. Yalnızca çift (“)
(çift ve üçlü çift) alıntı dizeler enterpolasyonu
destekler.
Üçlü tırnaklı (üçlü tekli ve üçlü çiftli) dizeler çok
satırlıdır ve dizenin içeriğini, çizgi veya yeni satır
kaçış karakterleri olmadan birkaç parçaya
bölmeye gerek kalmadan, çizgi sınırlarına
dağıtabilirsiniz.
Çift tırnak (“) (çift tırnak ve üçlü çift tırnak) ile
tanımlanan dizeler enterpolasyonu destekler. Bu,
herhangi bir Groovy ifadesini belirtilen konumdaki
bir string ile değiştirmenize olanak tanır. Bunlara
GStrings denir.
Bu, ${} sözdizimi kullanılarak gerçekleştirilir.
GStrings, sabit ve dinamik parçaları (değerleri)
aşağıdaki örnekte gösterildiği gibi ayrı ayrı
yakalamak için farklı şekilde uygulanır.
// Groovy’de Metot Tanımlamak
def say(mecburi, secimli = 'world') {
def yerel_degisken = 12
def_siz_de_olur = "21"
return "$mecburi $secimli! $yerel_degisken"
}
// say(), say(msg), say(msg, name)
assert 'Hello world!' == say()
assert 'Hi world!' == say('Hi')
assert 'Howdy, mrhaki!' == say('Howdy,', 'mrhaki')
// Boolean Evaluation
println "****** Boolean Evaluation ******"
def degisken = "0" // == "" için false, diğer değerler için true
println "degisken: ${degisken as Boolean}"
if(!(degisken as Boolean))
println "> false: degisken: "${degisken}""
else
println "> true: degisken: "${degisken}""
// Integer Evaluation
println "n****** Integer Evaluation ******"
degisken = "31"
def sayi = degisken?.isInteger() ? ++(degisken as Integer) : null
println "> degisken: "${degisken}" > ${sayi}"
String metinle99 = "99"
sayiyla99 = Integer.parseInt(metinle99)
println "> Metinle: "${metinle99}" > ${sayiyla99}"
// Float Evaluation
println "n****** Float Evaluation ******"
degisken = "3.1"
sayi = degisken?.isFloat() ? ++(degisken as Float) : null
println "> degisken: "${degisken}" > ${sayi}"
// Single vs Double Quotes
println "n****** Single vs Double Quotes ******"
println 'hi'.class.name // java.lang.String
println "hi".class.name // java.lang.String
def a = 'Freewind'
println "hi $a" // "hi Freewind"
println 'hi $a' // "hi Freewind"
println "hi $a".class.name // org.codehaus.groovy.runtime.GStringImpl
// Static import
import static java.lang.Integer.parseInt as int_e_cevir
println int_e_cevir("12")
Değişkene Metot Atamak
Fonksiyona Parametre Olarak Fonskiyon Geçmek
Callback Fonksiyonu Parametre olarak Geçirmek
def CALLBACK(){
println "İlk fonksiyon CALIS işletidi..."
// değişken olarak fonksiyon/metot tanımlamak
def HEDE = { println "heedeeee" }
HEDE()
}
def CALIS( Closure cb){
println "İlk fonksiyon CALIS işletidi..."
cb()
}
CALIS(this.&CALLBACK)
String Manipulasyonları
+ Operator
'My name is ' + first + ' ' + last
GString
"My name is $name"
Interpolasyon
"My name is ${name}"
concat() Fonksiyonu
'My name is '.concat(first).concat(' ').concat(last)
leftShift() veya << Operator
'My name is ' << first << ' ' << last
StringBuilder() Tipi
new StringBuilder().append('My name is ').append(first).append(' ').append(last)
StringBuffer() Tipi
new StringBuffer().append('My name is ').append(first).append(' ').append(last)
Çok Satırlı String
name.first = '''
Joe
Smith
''';
name.last = 'Junior'
.split()
String[] arr = metin.split()
arr.each { b -> println(b) }
2 Dizinin Birleştirilmesi
def first = ["a", "b", "c"]
def second = ["d", "e", "f"]
first.addAll(second)
def third = first + second
// ["a", "b", "c", "d", "e", "f"]
Array Fonksiyonları
Array: join() Metodu
['My name is', first, last].join(' ')
Array: inject() Metodu
[first,' ', last]
.inject(new StringBuffer('My name is '), { initial, name -> initial.append(name); return initial }).toString()
Array Metotları
def metin = '''./projects/cinar/cn-nef
./projects/cinar/cn-nrf
./projects/cinar/cn-nssf'''
// Lambda fonksiyon (Closure) >>> ->{}
def eachFonksiyonu = {
a ->
String ilkBes = a.substring(0,4)
println(ilkBes)
}
metin.split().each eachFonksiyonu
metin.split().each { b -> println(b) }
Array - .max()
Integer[] intArray = [200, 300, 100]
println intArray.max()
String[] stringArray = ["A", "B", "C"]
println stringArray.max()
Array - .min()
Integer[] intArray = [200, 300, 100]
println intArray.min()
String[] stringArray = ["A", "B", "C"]
println stringArray.min()
Array - .sort()
Integer[] intArray = [200, 300, 100]
println intArray
intArray.sort()
println intArray
Array - .reverse()
String[] stringArray = ["A", "B", "C"]
String[] reverseArray = stringArray.reverse()
println stringArray
println reverseArray
Array - .size() == .length
Integer[] arr= [200, 300, 100]
println(arr.length + " == " + arr.size())
Array - [index] == .getAtt(index)
Integer[] arr= [200, 300, 100]
println(arr[0] + " == " + arr.getAt(0))
Array to List
def list = [
'green bay',
'packers',
'cincinnati',
'bengals'] as
Object[]
def map = list.toSpreadMap()
null Elemanları Sil
def col = [
89, 32, null, 55
]
def r = col - null
r = col.minus(null)
// [89, 32, 55]
List
Liste, veri öğelerinin bir koleksiyonunu
saklamak için kullanılan bir yapıdır.
Groovy'de Liste, bir dizi nesne başvurusu
içerir. Listedeki nesne başvuruları,
dizideki bir konumu işgal eder ve bir
tamsayı dizini ile ayırt edilir.
Dizin esasına göre öğe ekleme ve silme
yöntemlerini içeren Koleksiyonun bir alt
arabirimidir.
Groovy listeleri düz JDK
java.util.List dir, çünkü Groovy
kendi koleksiyon sınıflarını tanımlamaz.
Çok boyutlu listeler de oluşturabilirsiniz.
Değerleri virgülle sınırlayan ve köşeli
parantez içine alan bir liste
başlatabilirsiniz. Heterojen türlerin
değerlerini içeren listeler de
oluşturabilirsiniz.
- Listenin ilk öğesine sıfır tabanlı sayım üzerinden
erişebilirsiniz: hetero [0]
- Listenin son öğesine negatif bir dizinle erişebilirsiniz: hetero [-
1]
- Listeye bir öğe ekleyin: numbers [3] = 5
- Listenin boyutu: numbers.size () == 4
SET
Map
Range
Loop
for Loop
for (i = 0; i <3; i++) {
System.out.println("Hello World")
}
for Loop With Collection
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
for (String item : list) {
System.out.println(item)
}
For Loop with Upto
def c = {
println it
}
1.upto(4, c)
Çıktı
1
2
3
4
1.upto(4, {
println "Number ${it}"
})
For Loop with Step
0.step 5, 1, {
println it
}
Çıktı
0
2
4
0.step 5, 2, {
println it
}
For Loop with Times
3.times {
println "Hi ${it}"
}
Çıktı
Hi 0
Hi 1
Hi 2
def n = 3
n.times {
println "Hello ${it}"
}
For in
for(item in ["A", "B"])
{
println item
}
Çıktı
1
2
3
for (number in 1..3 )
{
println number
}
For map
def map = [a1:'b1', a2:'b2']
for ( item in map ) {
println item.key
println item.value
println
}
Çıktı
a1
b1
a2
b2
collectEntries Loop
def index = 0
def result = ["bir":1,"iki":2].collectEntries { key, val->
return ["${key}_${++index}": val]
// veya aşağıdaki gibi return olmaksızın dönüş sağlanabilinir.
// ["${key}_${++index}": val]
}
println result // [bir_1:1, iki_2:2]
Düzenli İfadeler RegExp
~// ile Düzenli İfade Tanımlamak
def ipAddress = ~/([0-9]+.[0-9]+.[0-9]+.[0-9]+)/
println ipAddress.class.name // java.util.regex.Pattern
ipAddress değişkeni otomatik olarak regex.Pattern olmuş!
Eşleşti mi?
def nameRegex = ~’john’
println nameRegex.matcher("john").matches() // true
def ipAddressRegex = ~/([0-9]+.[0-9]+.[0-9]+.[0-9]+)/
println ipAddressRegex.matcher("127.0.0.1").matches() // true
Jenkins
sh
SH
sh Komutu
script (opt.boolean):
returnStdout (opt.boolean): Returns the standard output stream with a default encoding
of UTF-8 (alternative encoding is optional)
returnStatus (opt. boolean): Returns the exit status (integer) of the PowerShell
script
0 Olmayan exit kodları hatalı olarak script sonlandı demektir. Buna göre tüm jenkins
build’i hakkında işaretleme yapabilir, sonraki işlere devam edebilir ya da
kesebiliriz.
def statusCode = sh script:script, returnStatus:true
currentBuild.result = 'FAILURE'
currentBuild.result = 'UNSTABLE'
label (opt. string): Label to be displayed in the pipeline step view and blue ocean
details for the step instead of the step type. So the view is more meaningful and
domain specific instead of technical.
encoding (opt. string): Eğer returnStdout: true olarak işaretlenmişse sh’ın çıktısını
okuyacağız demektir ve okunacak metnin kodlaması default olarak UTF-8 olmasına rağmen
değiştirilebilir (encoding: 'UTF-8')
For Loop with Upto
def c = {
println it
}
1.upto(4, c)
Çıktı
1
2
3
4
1.upto(4, {
println "Number ${it}"
})
For map
def map = [a1:'b1', a2:'b2']
for ( item in map ) {
println item.key
println item.value
println
}
Çıktı
a1
b1
a2
b2
try {
npmViewOutput = sh(returnStdout: true, script: "npm view olmayan_paket")
} catch (Exception e) {
echo "${e.message}"
}
Jenkins
Değişken
Tanımlama
Değişken Tanımlama
Jenkinsfile dosyasındaki değişkenler def
anahtar sözcüğü kullanılarak
tanımlanabilir. Bu değişkenler pipeline
bloğu başlamadan önce tanımlanmalıdır.
Değişken tanımlandığında, ${...}
sözdizimi kullanılarak Jenkins
declarative script düzeninden
çağrılabilir.
Globalde tanımlı değiken adı yerelde
tekrar tanımlanamaz!
The current scope already contains a
variable of the name myVar
def myVariable = "foo"
pipeline {
agent any
stages {
stage ("Print variable") {
steps {
echo "My variable is ${myVar}"
}
}
}
}
Koşullu Değişkenler
Groovy dili, Jenkins pipeline’da
kullanılabilen koşullu yapıları destekler.
Parametreli bir job ve bir Jenkinsfile
dosyasında, sağlanan parametrelere bağlı
olarak tanımlanması gereken bir
değişkeniniz olduğunu varsayın.
// Define variables
// and convert them to lowercase
def role = params.ROLE.toLowerCase()
def env = params.ENVIRONMENT.toLowerCase()
// Conditionally define a variable 'impact'
if (role == 'front' && env == 'prod') {
impact = "high"
} else if (role == 'front' && env == 'dev') {
impact = "low"
} else if (role == 'db' && env == 'stg') {
impact = "medium"
} else {
impact = "unknown"
}
// 'impact' değişkenini Jenkins pipeline’a yaz
pipeline {
agent any
stages {
stage ("Impact") {
steps {
echo "The impact is ${impact}"
}
}
}
}
Koşullu Çalışacak Aşamalar
Eğer dosya varsa (fileExists) aşama
çalıştırılacak, yoksa başka bir aşama
çalıştırılacak.
Environment 3 şekilde tanımlanıyordu,
global olanı Jenkins Global Properties
içinde Environment Variables alanında.
Inject edilebilen env. var. EnvInject
plugin sayesinde. Ve local env. değişken
olarak pipeline içinde tanımlanır.
pipeline{
agent any
environment{
MY_FILE = fileExists '/tmp/myfile'
}
stages{
stage('dosya varsa aşaması'){
when {
expression { MY_FILE == 'true' }
}
steps {
echo "file exists"
}
}
stage('Dosya yoksa aşaması'){
when {
expression { MY_FILE == 'false' }
}
steps {
echo "file does not exist"
}
}
}
}
def myVar = "globalde tanımlı"
...
stage ("yerel") {
steps {
def myVar = "2. kez olmaz"
}
}
findFiles ile Dosya Bulmak
def files = findFiles glob: '**/reports/*.json'
for (def i=0; i<files.length; i++) {
jsonFilePath = "${files[i].path}"
jsonPath = "${env.WORKSPACE}" + "/" + jsonFilePath
echo jsonPath
readJSON ile JSON dosyasını/metnini değişkene atama yap
stages {
stage('readJSON angular.json') {
steps{
script {
def json = readJSON file: './angular.json'
def projects = json['projects']
projects = json.projects
if(json.projects){
// sadece e2e testleri olan projeleri MAP içinde saklayalım
def e2eProjeleri = [:]
json.projects.each { key, value ->
println "KEY:" + key + " <> VALUE:" + value.projectType
println " >> value.architect.e2e: "+value.architect.e2e
// value.architect.e2e değeri null olduğunda falsey değer olacaktır.
// Aksi halde truthy olacak ve if şartına girecek
if(value.architect.e2e){
e2eProjeleri[key] = [a: value.architect.e2e, b: "cem"]
}
}
e2eProjeleri.each{ k, v -> println k }
}
}
}
}
}
readJSON ve returnPojo ile LinkedHashMap veya JSONObject türüne dönüştürmek
Jenkins
Environment
Variables
Environment Variable
İşletim sisteminin ortam değişkenlerine windows için
%DeğişkenAdı% , linux için $DeğişkenAdı ile erişiyoruz.
Ortam değişkenleri tüm hat içerisinden erişilebilen yerel ve
global değişkenlerdir.
İşletim sistemi seviyesinde tanımlı env. vars’a erişmek için
windows os üstünde koşan bir batch için $env.PATH,
Nasıl ve hangi sırayla eziliyor env vars?
def PATH = "En üstte tanımlı global degisken"
pipeline {
agent any
stages {
stage("a"){
environment{ PATH = "local env. var. PATH" }
steps{
/**
* $env.XXX ile değişkenler;
* varsa
* önce local env,
* sonra Jenkins env
* sonra OS env
* seviyesinde PATH değişkenin arar
*
* localde env.PATH bulur ve onu yazar **/
echo "$env.PATH"
}
}
stage("b"){
// önce değikenlerde arar ve globalde PATH değişkeni bulur
steps{ echo "$PATH" }
}
stage("c"){
environment { PATH = "yerel env içinde tanımlı" }
// env.PATH olmadığı için önce değikenlerde arar. Local'de PATH adında değişken yok!
// globalde (en üstte) tanımlı PATH değişkenini bulur
steps{ echo "$PATH" }
}
stage("ç"){
// Local env de PATH yok. Jenkins seviyesinde env.PATH bulur onu yazar
steps{ echo "$env.PATH" }
}
stage("d"){
environment{ PATH = "Ezdi mi ne?" }
// local env.PATH bulur ve onu yazar
steps{ echo "$env.PATH" }
}
}
Env Var Sıralaması
$env.XXX ile erişilmek istenen ortam
değişkenleri aşağıdaki sıralama ile
aranır. İlk bulunduğu yerde değeri
kullanılır. Bulunamazsa değer olara null
kullanılır.
stage("a"){
environment{
PATH = "local env. var. PATH"
}
steps{
/**
* $env.XXX ile değişkenler;
* varsa
* önce local env,
* sonra Jenkins env
* sonra OS env
* seviyesinde PATH değişkenin arar
**/
echo "$env.PATH"
}
Global ve Local Değişkenler ve Local Ortam Değişkenleri
def global_degisken = "En üstte tanımlı global degisken"
pipeline {
agent any
stages {
stage("a"){
environment{
aDegiskeni = "A"
}
steps{
echo "------- STAGE A >>>>>>>>>>>"
echo "global_van: $global_degisken"
echo "local env aDegiskeni: “
echo "$aDegiskeni = $env.aDegiskeni = ${env.aDegiskeni} = ${aDegiskeni}"
/** bDegiskeni tanımlı olmadığı için hata verir
* groovy.lang.MissingPropertyException:
* No such property: bDegiskeni for class: groovy.lang.Binding
* echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni"
*/
echo "<<<<<<<<<< STAGE A --------------"
}
}
stage("b"){
environment{
bDegiskeni = "B"
}
steps{
echo "------- STAGE B >>>>>>>>>>>"
echo "global_van: $global_degisken"
/** aDegiskeni yerelde veya globalde tanımlı bir değişken olsa erişilebilir.
* Oysa A aşamasında env'e bağlı yaratlıyor ancak burada env olmadan
* yani $aDegiskeni veya = ${aDegiskeni} diyerek erişilmek isteniyor
* Bu yüzden istisna fırlatacak ve build son bulacak.
* groovy.lang.MissingPropertyException:
* No such property: aDegiskeni for class: groovy.lang.Binding
*/
echo "local env aDegiskeni: $env.aDegiskeni = ${env.aDegiskeni}"
echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni"
echo "<<<<<<<<<< STAGE B --------------"
}
}
}
}
env-vars.html
${YOUR_JENKINS_HOST}/env-vars.html
shell Komutuyla
pipeline {
agent any
stages {
stage("Env Variables") {
steps {
sh "printenv"
}
}
}
}
ortam değişkenlerine değer atamak
pipeline {
agent any
environment { FOO = "bar" }
stages {
stage("Env Variables") {
environment { NAME = "Alan" }
steps {
echo "FOO = ${env.FOO}"
script {
env.TEST_VARIABLE = "some test value"
}
echo "TEST_VARIABLE = ${env.TEST_VARIABLE}"
withEnv(["BASKA_ENV_VAR=başka değer"]) {
echo "BASKA_ENV_VAR = ${env.BASKA_ENV_VAR}"
}
} } } }
ortam değişkenlerinde BOOLEAN
script {
if (env.IS_BOOLEAN) {
echo ""false" String Boolean.TRUE değerine dönüşür"
}
if (env.IS_BOOLEAN.toBoolean() == false) {
echo ""false".toBoolean() ise Boolean.FALSE olur"
}
}
ortam değişkenlerine shell’den değer atamak
pipeline {
agent any
environment {
LS = "${sh(script:'ls -lah', returnStdout: true)}"
}
stages {
stage("Env Variables") {
steps {
echo "LS = ${env.LS}"
}
}
}
}
ortam değişkenlerini okumak
Yerelde tanımlı olmayan değişkeni global de ve en üstte ortam değişkenlerinde arar.
pipeline {
agent any
stages {
stage("Env Variables") {
steps {
echo "1. Yöntem: ${env.BUILD_NUMBER}"
echo "2. Yöntem: ${BUILD_NUMBER} -> ${BUILD_NUMBER}"
sh 'echo "3. Yöntem: $BUILD_NUMBER"'
} } } }
pipeline {
agent any
environment {
FOO = "bar"
NAME = "Joe"
}
stages {
stage("Env Variables") {
environment {
NAME = "Alan" // overrides pipeline level NAME env variable
BUILD_NUMBER = "2" // overrides the default BUILD_NUMBER
}
steps {
echo "FOO = ${env.FOO}" // prints "FOO = bar"
echo "NAME = ${env.NAME}" // prints "NAME = Alan"
echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 2"
script { env.SOMETHING = "1" // creates env.SOMETHING variable }
}
}
stage("Override Variables") {
steps {
script {
env.FOO = "IT DOES NOT WORK!" // it can't override env.FOO declared at the pipeline (or stage) level
env.SOMETHING = "2" // it can override env variable created imperatively
}
echo "FOO = ${env.FOO}" // prints "FOO = bar"
echo "SOMETHING = ${env.SOMETHING}" // prints "SOMETHING = 2"
withEnv(["FOO=foobar"]) { // it can override any env variable
echo "FOO = ${env.FOO}" // prints "FOO = foobar"
}
withEnv(["BUILD_NUMBER=1"]) {
echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 1"
}
}
}
}
}
Globalde Tanımlı Özel Env. Var.
Jobların erişmesini istediğiniz
temel değerleri global env.
vars. içinde
tanımlayabilirsiniz. Örneğin
sprint koşunuzun numarası,
üretilecek projenin versiyon
numarası vs. için değerleri
globalde bir kere tanımlayıp
tüm projeler için globaldeki
değişkenler gibi (örneğin
BUILD_NUMBER’a WORKSPACE’e
erişir gibi) erişebilirsiniz.
Jenkins
Dekleratif Pipeline
Örneği
Declrative Jenkins
Yeni bir proje
başlatıyor ve
pipeline
türünde seçerek
adını
yazıyoruz.
Daha sade bir yapıda gelecek. Pipeline
içinde scriptimizi yazıyoruz. Yardıma
ihtiyacımız olduğu yerlerde “Pipeline
Syntax” bağlantısından bizim için script
üretmesini isteyebiliriz.
pipeline {
}
İlk ifademiz pipeline olacak
ve tüm yönergelerimiz
pipeline bloğunun içinde
olmalıdır
Declarative Pipeline’ı Anlamak
pipeline {
agent any
}
Herhangi uygun agent üstünde
çalışacak diye işaretledik.
Etikete göre agent seçmek:
agent { label '!windows' }
pipeline {
agent any
tools {
git ‘localGit’
jdk ‘localJava’
nodejs ‘localNode’
}
}
Jenkins'te kullanılacak
araçları tools ile belirtiriz.
Araçlar (tools), Jenkins
düğümünde yüklü olan
yapılandırma (build)
araçlarından başka bir şey
değildir.
Global Tool Configuration
altında belirttiğimiz
çalıştırılabilir uygulamaların
yollarını takma adlarla
tanımlamıştık. tools Altındaki
araçlar için bu takma adları
kullanıyoruz.
pipeline {
agent any
environment {
global_degisken = 'true'
}
stages {
stage ('derle') {
environment {
yerel_degisken = '12'
}
steps {
echo 'Değer: '+yerel_degisken
}
}
}
}
Ortam değişkenleri global veya stage
özelinde ayarlanabilir. Stage başına
ayarlanmış değişkenler sadece tanımlı
olunan stage için geçerli olacaktır.
Global Tool Configuration altında
belirttiğimiz çalıştırılabilir
uygulamaların yollarını takma adlarla
tanımlamıştık. tools Altındaki
araçlar için bu takma adları
kullanıyoruz.
DSL ile Jenkins Script arasındaki fark;
daha kolay kodlama yapabileceğimiz
Domain Specific Language olarak
tanımlayabiliriz.
Declarative Jenkins Pipeline
(1) Pipeline türünde bir proje
başlatalım. İçinde Jenkinsfile (4)
adında dosya ve aşamaları
barındıran bir script dosyası da
olacak github projesi (2)
oluşturalım. Jenkins job’ının
içinde Pipeline kısmında bir
Source Control Management (3)
üstünden Jenkinsfile dosyasını
çekeceğimizi belirtelim.
Çalıştırdığımızda git çekilir ve
Jenkinsfile çalıştırılır(5).
1
2
3
4
5
bat 'powershell -noexit "& "".run-tests.ps1"""'
steps {
echo "build içindeki steps"
bat "echo %path%"
bat "sh --help"
bat "npm --version && npm
start"
}
'cmd' is not recognized as an internal or external command, operable program
or batch file.
İster stage içinde ister tüm pipeline içindeki environment ayarına
cmd.exe dosyasını erişilebilir hale getirmeli:
environment {
PATH = "C:WINDOWSSYSTEM32;"
}
'npm' is not recognized as an internal or external command, operable program
or batch file.
npm adında çalıştırılabilir dosyayı erişilebilir hale getirmek için
NodeJS aracını tools altına eklemeli:
tools {
nodejs "node_js" // Global Conf. Tools altında tanımlı araç adı
}
Ok-Cancel Sorusu sormak için input message kullanılır
input message: "Devam etmek için Proceed bağlantısına tıkla, iptal için Abort'a tıkla"
pipeline {
agent none
stages {
stage('Integration Test') {
agent { label
'windows_agent' }
steps {
script {
docker.image('mongo:3.4').withRun(' -p
27017:27017') { c ->
sh "echo
ayaklandı"
}
}
}
}
}
}
Hata Yönetimi
(ERROR)
error
Kendimiz hata uydurmak istersek
error(mesajımız) fonksiyonunu
kullanırız.
try {
error("Hata mesajı")
} catch (e) {
echo 'Hata: ' + e.toString()
throw e
} finally {
// çalışır
}
try-catch-finally
stage('checkout') {
try {
…
if (your condition) {
autoCancelled = true
error('Kritik hata oluştu')
}
} catch (e) {
if (e.message == "Devam edilecek istisna") {
currentBuild.result = 'ABORTED'
echo('return yaparsak sonraki stage çalışır')
return
}
echo('throw yaparsak sonraki stage çalışmaz')
throw e
} finally {
echo('her şeye rağmen çalıacak satır')
}
}
retry(n)
retry(2) {
try {
prepareEnvironment()
setupBuildEnvironment()
// sets up environment if it is not present yet
runBuild()
} catch (e) {
echo 'Err: Build failed with Error: ' +
e.toString()
echo ' Trying to build with a clean Workspace'
removeOldBuildEnvironment()
throw e
} finally {
cleanupEnvironment()
}
}
catchError
Birden fazla projenin kullandığı ortak kütüphanede mi değişiklik yaparak hepsini etkilemek istersiniz yoksa
tek tek her projeye gidip değişiklik mi yapmak istersiniz?
Shared Library
Neden Shared library?
Birden fazla projenin kullandığı ortak kütüphanede mi değişiklik yaparak hepsini etkilemek istersiniz yoksa
tek tek her projeye gidip değişiklik mi yapmak istersiniz?
Paylaşılan kitaplık deposu klasör yapısına sahiptir.
(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global 'foo' variable
+- resources # resource files
| +- org
| +- foo
| +- bar.json # static helper data for org.foo.Bar
Jenkins Notlarım

More Related Content

What's hot

Build CICD Pipeline for Container Presentation Slides
Build CICD Pipeline for Container Presentation SlidesBuild CICD Pipeline for Container Presentation Slides
Build CICD Pipeline for Container Presentation SlidesAmazon Web Services
 
Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介QlikPresalesJapan
 
DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...
DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...
DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...Edureka!
 
Intro to Kubernetes & GitOps Workshop
Intro to Kubernetes & GitOps WorkshopIntro to Kubernetes & GitOps Workshop
Intro to Kubernetes & GitOps WorkshopWeaveworks
 
Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...
Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...
Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...Edureka!
 
The journey to GitOps
The journey to GitOpsThe journey to GitOps
The journey to GitOpsNicola Baldi
 
OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)
OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)
OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)NTT DATA OSS Professional Services
 
Get started with gitops and flux
Get started with gitops and fluxGet started with gitops and flux
Get started with gitops and fluxLibbySchulze1
 
DevOps avec Ansible et Docker
DevOps avec Ansible et DockerDevOps avec Ansible et Docker
DevOps avec Ansible et DockerStephane Manciot
 
Gitlab flow solo
Gitlab flow soloGitlab flow solo
Gitlab flow soloviniciusban
 
Speeding up your team with GitOps
Speeding up your team with GitOpsSpeeding up your team with GitOps
Speeding up your team with GitOpsBrice Fernandes
 
Version control system
Version control systemVersion control system
Version control systemAndrew Liu
 
From DevOps to GitOps with GitLab
From DevOps to GitOps with GitLabFrom DevOps to GitOps with GitLab
From DevOps to GitOps with GitLabChen Cheng-Wei
 
Qlik Sense SaaSのオンボーディング
Qlik Sense SaaSのオンボーディングQlik Sense SaaSのオンボーディング
Qlik Sense SaaSのオンボーディングQlikPresalesJapan
 
GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축철구 김
 
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介QlikPresalesJapan
 
How to build a Kubernetes networking solution from scratch
How to build a Kubernetes networking solution from scratchHow to build a Kubernetes networking solution from scratch
How to build a Kubernetes networking solution from scratchAll Things Open
 

What's hot (20)

Build CICD Pipeline for Container Presentation Slides
Build CICD Pipeline for Container Presentation SlidesBuild CICD Pipeline for Container Presentation Slides
Build CICD Pipeline for Container Presentation Slides
 
Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介Qlik Cloudデータ統合:データ変換機能のご紹介
Qlik Cloudデータ統合:データ変換機能のご紹介
 
DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...
DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...
DevOps Testing | Continuous Testing In DevOps | DevOps Tutorial | DevOps Trai...
 
Intro to Kubernetes & GitOps Workshop
Intro to Kubernetes & GitOps WorkshopIntro to Kubernetes & GitOps Workshop
Intro to Kubernetes & GitOps Workshop
 
GitOps with Gitkube
GitOps with GitkubeGitOps with Gitkube
GitOps with Gitkube
 
Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...
Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...
Chef vs Puppet vs Ansible vs SaltStack | Configuration Management Tools Compa...
 
The journey to GitOps
The journey to GitOpsThe journey to GitOps
The journey to GitOps
 
OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)
OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)
OpenJDKは使い物になるか?OpenJDKの実際と今後 (NTTデータ オープンソースDAY 2015 Autumn 講演資料)
 
Get started with gitops and flux
Get started with gitops and fluxGet started with gitops and flux
Get started with gitops and flux
 
DevOps avec Ansible et Docker
DevOps avec Ansible et DockerDevOps avec Ansible et Docker
DevOps avec Ansible et Docker
 
Gitlab flow solo
Gitlab flow soloGitlab flow solo
Gitlab flow solo
 
Speeding up your team with GitOps
Speeding up your team with GitOpsSpeeding up your team with GitOps
Speeding up your team with GitOps
 
Version control system
Version control systemVersion control system
Version control system
 
From DevOps to GitOps with GitLab
From DevOps to GitOps with GitLabFrom DevOps to GitOps with GitLab
From DevOps to GitOps with GitLab
 
Qlik Sense SaaSのオンボーディング
Qlik Sense SaaSのオンボーディングQlik Sense SaaSのオンボーディング
Qlik Sense SaaSのオンボーディング
 
GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축GitLab과 Kubernetes를 통한 CI/CD 구축
GitLab과 Kubernetes를 통한 CI/CD 구축
 
CICD with Jenkins
CICD with JenkinsCICD with Jenkins
CICD with Jenkins
 
CICD with Jenkins
CICD with JenkinsCICD with Jenkins
CICD with Jenkins
 
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
リアルタイムにデータを配信・変換・統合:Qlik Cloudデータ統合のご紹介
 
How to build a Kubernetes networking solution from scratch
How to build a Kubernetes networking solution from scratchHow to build a Kubernetes networking solution from scratch
How to build a Kubernetes networking solution from scratch
 

Similar to Jenkins Notlarım

React Bootcamp Day 1 - Yunus Demirpolat
React Bootcamp Day 1 - Yunus DemirpolatReact Bootcamp Day 1 - Yunus Demirpolat
React Bootcamp Day 1 - Yunus Demirpolatkloia
 
Continuous Integration Bamboo ve Php Uygulaması
Continuous Integration Bamboo ve Php UygulamasıContinuous Integration Bamboo ve Php Uygulaması
Continuous Integration Bamboo ve Php UygulamasıMustafa Ileri
 
Building the continuous integration layer in Avea
Building the continuous integration layer in AveaBuilding the continuous integration layer in Avea
Building the continuous integration layer in AveaOguzhan Ozavar
 
Visual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleri
Visual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleriVisual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleri
Visual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleriMurat Başeren
 
Release Management
Release ManagementRelease Management
Release ManagementOzgur Birol
 
ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)
ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)
ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)İbrahim ATAY
 
Çevik Manifesto Sunum
Çevik Manifesto Sunum Çevik Manifesto Sunum
Çevik Manifesto Sunum ERCAN CETIN
 
Yazılım Mimarileri - Yazılım Geliştirme Modelleri
Yazılım Mimarileri - Yazılım Geliştirme ModelleriYazılım Mimarileri - Yazılım Geliştirme Modelleri
Yazılım Mimarileri - Yazılım Geliştirme ModelleriKubra Kose
 
Yazılım mimarisi yazılım müh.
Yazılım mimarisi yazılım müh.Yazılım mimarisi yazılım müh.
Yazılım mimarisi yazılım müh.Hüseyin Örer
 
Yazilim Gelistirme Yöntemleri
Yazilim Gelistirme YöntemleriYazilim Gelistirme Yöntemleri
Yazilim Gelistirme Yöntemlerim_korkmaz
 
Android mimari-cekirdek-binding-scheduler
Android mimari-cekirdek-binding-schedulerAndroid mimari-cekirdek-binding-scheduler
Android mimari-cekirdek-binding-schedulerErcan Pinar
 
SVN & CVS by Eren SIMSEK
SVN & CVS by Eren SIMSEKSVN & CVS by Eren SIMSEK
SVN & CVS by Eren SIMSEKerensimsek
 
Test Driven Development
Test Driven Development Test Driven Development
Test Driven Development Nezir Yürekli
 
Abapgit kurulum kullanım
Abapgit kurulum kullanımAbapgit kurulum kullanım
Abapgit kurulum kullanımEliflknurNACAR
 

Similar to Jenkins Notlarım (20)

Jenkins
JenkinsJenkins
Jenkins
 
Sunum tdd
Sunum tddSunum tdd
Sunum tdd
 
React Bootcamp Day 1 - Yunus Demirpolat
React Bootcamp Day 1 - Yunus DemirpolatReact Bootcamp Day 1 - Yunus Demirpolat
React Bootcamp Day 1 - Yunus Demirpolat
 
Continuous Integration Bamboo ve Php Uygulaması
Continuous Integration Bamboo ve Php UygulamasıContinuous Integration Bamboo ve Php Uygulaması
Continuous Integration Bamboo ve Php Uygulaması
 
Building the continuous integration layer in Avea
Building the continuous integration layer in AveaBuilding the continuous integration layer in Avea
Building the continuous integration layer in Avea
 
Visual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleri
Visual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleriVisual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleri
Visual studio 2010 ve tfs 2010 yeni takim gelistirme ozellikleri
 
Release Management
Release ManagementRelease Management
Release Management
 
Visual Studio Developer Tools
Visual Studio Developer ToolsVisual Studio Developer Tools
Visual Studio Developer Tools
 
Selenium
SeleniumSelenium
Selenium
 
ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)
ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)
ASP.Net MVC ile Web Uygulamaları -12(Test Drive Developmet)
 
Çevik Manifesto Sunum
Çevik Manifesto Sunum Çevik Manifesto Sunum
Çevik Manifesto Sunum
 
Yazılım Mimarileri - Yazılım Geliştirme Modelleri
Yazılım Mimarileri - Yazılım Geliştirme ModelleriYazılım Mimarileri - Yazılım Geliştirme Modelleri
Yazılım Mimarileri - Yazılım Geliştirme Modelleri
 
Yazılım mimarisi yazılım müh.
Yazılım mimarisi yazılım müh.Yazılım mimarisi yazılım müh.
Yazılım mimarisi yazılım müh.
 
Yazilim Gelistirme Yöntemleri
Yazilim Gelistirme YöntemleriYazilim Gelistirme Yöntemleri
Yazilim Gelistirme Yöntemleri
 
Android mimari-cekirdek-binding-scheduler
Android mimari-cekirdek-binding-schedulerAndroid mimari-cekirdek-binding-scheduler
Android mimari-cekirdek-binding-scheduler
 
Software/Yazılım Test
Software/Yazılım TestSoftware/Yazılım Test
Software/Yazılım Test
 
SVN & CVS by Eren SIMSEK
SVN & CVS by Eren SIMSEKSVN & CVS by Eren SIMSEK
SVN & CVS by Eren SIMSEK
 
Test Driven Development
Test Driven Development Test Driven Development
Test Driven Development
 
Abapgit kurulum kullanım
Abapgit kurulum kullanımAbapgit kurulum kullanım
Abapgit kurulum kullanım
 
Cevik Yaklasim, Scrum ve XP Pratikleri
Cevik Yaklasim, Scrum ve XP PratikleriCevik Yaklasim, Scrum ve XP Pratikleri
Cevik Yaklasim, Scrum ve XP Pratikleri
 

Jenkins Notlarım

  • 2. En Basit Haliyle Nasıl Çalışır?
  • 4. Master & Slave Yapısı
  • 6. Continuous Delivery - Sürekli Teslimat "Continuous Delivery doesn't mean every change is deployed to production ASAP. It means every change is proven to be deployable at any time." Carl Caum from the Puppet Blog "Continuous Delivery means a team can deploy a feature whenever a product owner approves the feature and wants to deploy it." To be able to tell your product owner they can do this, does take time for the team to institute the right practices to enable CD*. Sürekli Teslimat, deploy etmek zorunda olmadığın ama her zaman buna hazır olabildiğin andır.
  • 7. Continuous Delivery Continus Delivery aşağıdaki üç disiplinin kombinasyonu demektir - Continuous Integration - Continuous Testing - Continuous Deployment (istendiğinde) Bu sürece konfigurasyon yönetimi de gelecek.
  • 8. Continuous Delivery Hedefler Kullanıcıya çalışan yazılımı olabildiğince hızlı verebilmek Sıklıkla otomatize edilmiş sürümler sunmak Faydalar Düşük risk, stres Hızlı yatırımın geri dönüşü (ROI) İş ihtiyaçlarına geliştirilmiş yanıt verebilmek İyileştirilmiş kalite Hızlıca hataya düşmek (fail-fast) Yüksek özgüven
  • 9. Delivery vs. Deployment Sırf yazılımcı yazdığı kodun kullanıldığını görsün diye mutlu etmek ama geri dönüşü olmayan sonuçlardan dolayı patronu endişelendirmek için yapılır*. Daha çok cloud ortamında sunucularını hızlıca geri dönebilen, ortak componenti ve veritabanları olmayan, işin hatasız olacağını çok geniş verilerle, regresyonlarla koşan, business’ın “tüm sorumluluk bendedir, kesinti mesinti hepsinin hesabını ben veriyorum” diyebildiği şirketlerde kullanılır*.
  • 10. Continuous Delivery vs. Deployment Sürekli Teslimat(cDelivery), başarılı olan bir yapıyı (build) bir ortama atmanın bir yoludur. Burada teslimat ile dağıtım arasında bir nüans vardır. - Teslimat manual olarak, - dağıtım ise otomatik olarak yapılır. Sürekli teslimat düzgün bir şekilde uygulandığında, müşteriler her zaman standartlaştırılmış bir test sürecinden geçmiş hazır yapıya sahip olacaklardır. Continus Delivery aşağıdaki üç disiplinin kombinasyonu demektir - Continuous Integration - Continuous Testing - Continuous Deployment (istendiğinde) Bu sürece konfigurasyon yönetimi de gelecek.
  • 11. Delivery vs Deployment Delivery ile yapılan sürüm sonuçları geri alınamayacak ve hassas kararların verilmesini gerektiren, elle yapılacak sürümdür. Deployment ile yapılan sürüm otomatik olduğu için ya hassas kararların verilmesi gerekmeyen ya da arkasında ciddi testlerin yapılarak sonucun sorunsuz olacağına inanıldığı otomatik yapılan sürümdür.
  • 12. Continuous Integratıon Kodu alıp kaynak yönetim sisteminde derleyerek üstünde unit testleri ve otomatize edilmiş süreçlerden geçirip kodun sorunsuz olduğunu gördüğümüz süreçtir. Yazılan kodun, geliştirilen modülün — kısaca geliştirme ortamından çıka gelen bir parçanın — projeye dahil edilmesi esnasında bir takım süreçlerden geçirilmesine verilen isim. Bağımlılıkların repolardan indirilmesi, projeye dahil edilmesi, geliştirilen kod parçacığın testlerden (unit, integration, vs…) geçirilmesi, olası durumlara göre geliştiriciye veya işin sorumlusuna bilgi verilmesi (push notification, sms, mail, vs…), işin paketlenmesi gibi eylemlerin tamamı, genellikle bu kavramın bir parçası olarak hayatımızda yer ediyor*.
  • 13. Sürekli entegrasyon (Continuous Integration = CI), kod üzerinde yapılan her değişikliğin ardından, tüm sistemin çalışır durumda olduğunu, yapılan değişikliğin sistemin bazı bölümlerinde kırılmalara yol açmadığını tespit etmek için kullanılan yöntemdir. Kırılmaları birim testlerle tespit ederiz. Bu testler, yapılan değişikliğin neticesi olarak yeni bir yapı (build) hazırlandıktan sonra otomatik olarak çalıştırılır. Yapılan değişiklik yeni yapının bir parçası olduğu için, testlerde oluşan hatalar, yapılan değişikliğin sistemi kırdığı anlamına gelmektedir. Bu durumdan tüm programcılar haberdar edilerek, hatanın bir an önce giderilmesi ve testlerin her zaman olumlu sonuç vermesi sağlanır. Sürekli entegrasyon ile programcılar tarafından kod üzerinde yapılan çalışmalar neticesinde her zaman çalışır bir sürümün oluşması sağlanmış olur*. Özcan Acar - Sürekli Entegrasyon
  • 14. Özcan Acar - Neden Sürekli Entegre Edilmeli? Oluşturduğunuz yazılım sistemini sürekli entegre etmiyorsanız, zamanı gelince toptan entegre etmek zorundasınız. Bunun, neden yazılım hayatınızda karşılaşabileceğiniz en büyük sorun olabileceğini bir örnek vererek açıklamak istiyorum. Şimdi şunu hayal edin: Yeni bir otomobilin tasarlanması projesinde yer aldınız. Otomobil tasarlandı ve otomobili oluşturan parçalar 5 değişik ülkede, 20 değişik firma tarafından üretildi. Bu ülkelerde kullanılan uzunluk ve ağırlık birimleri (metre, kg vs.) değişik olabilir. Görev dağılımı esnasında yanlış anlamalardan dolayı üretilen parçalar birbirine uyumlu olmayabilir. Eğer tüm parçalar üretildikten sonra bir çırpıda tüm otomobili oluşturmak isterseniz, üretim sürecinde meydana gelen hataları daha önceden tespit edemediğiniz için, yamuk yumuk bir otomobil ortaya çıkacaktır. Ama üretim esnasında koordineli bir şekilde otomobili parça parça bir araya getirip, parçalar uyuşuyor mu diye kontrol etmiş olsaydınız, meydana gelen uyuşmazlıkları çok erken tespit ederek, gerekli değişiklikleri yapabilirdiniz. Bu yazılım sektörü için de geçerli. Oluşturulan sistem komponentleri ne kadar erken entegre edilirse, oluşan uyuşmazlıklar o kadar erken tespit edilir ve gerekli değişiklikler yapılabilir. Sürekli entegrasyon çevik süreçlerde çok önemli bir yazılım metodudur. Sistem üzerinde yapılan her değişiklik sürekli entegrasyonu otomatik olarak gerçekleştiren sunucu tarafından kontrol edilir. Yazılımda kırılmalar oluşması (compile hataları, eksik sınıflar vs.) durumunda, tüm ekip sürekli entegrasyon sunucusu tarafından uyarılır. Bu geribildirim sayesinde entegrasyonun ne safhada olduğu anlaşılır.
  • 15. Continuous Testing Derlenmiş kodun üstünde entegrasyon, fonksiyonel vb. testlerin geçirildiği ve koda güvenin sağlandığı süreçtir.
  • 17. Her iş bir diğerini tetikler, Eğer başarısız olan iş olursa tüm süreç başarısız olarak kesilir
  • 18. Boru Hattı davranışını anlamak için nasıl yürütüldüğü hakkında birkaç noktayı anlamalısınız. - Adımların (steps) dışında, tüm pipeline mantığı, Groovy koşulları, döngüler, vb. ister basit ister karmaşık olsun, düğüm (node) bloğunun içinde bile olsa master Jenkins üstünde koşar. - Adımlar (steps), uygun olan yerlerde iş yapmak için uygulayıcıları (executors) kullanabilirler, ancak her adım küçük de olsa master’a ek yük yükler. - Pipeline kodu Groovy olarak yazılır, ancak yürütme modeli derleme zamanında Devam Geçiş Stili'ne (CPS -Continuation Passing Style-) dönüştürülür. - Bu dönüşüm, pipeline için değerli güvenlik ve dayanıklılık sağlar, ancak bazı sıkıntılarla birlikte gelir: - Adımlar (steps) Java kodunu çağırabilir ve Java kodu sayesinde hızlı ve verimli bir şekilde çalışabilir, ancak Groovy normalden daha yavaş çalışır. - Groovy çok daha fazla bellek gerektirir, çünkü nesne tabanlı bir sözdizimi bellekte tutulur. - Boru hatları, master’ın fail olmasından kurtulabilmek için programı ve durumunu kalıcı hale getirir. Pipeline & Groovy’e Dair Bilinmesi Gerekenler
  • 20. Dağıtım Hattının Aşamaları Compile & Unit Tests Integration Tests Source Code Analysis Assembly & Packaging Publish Artifacts Commit Stage Acceptance Stage Promote / Retrieve Artifacts Deploy for Functional Testing Functional Tests User Acceptance Tests Deploy To Production
  • 22. Jenkins Mimarisi - Jenkins, her yazılım gibi bir işletim sistemi(host) üstünde koşar. - Java application container veya application server üstünde koşar (varsayılan olarak Jetty kullanır) - Jetty ve jenkinsi başlatma, durdurma ve izlemek için harici bir servis uygulaması çalışır. - Views ile projeleri(jobs olarak da bilinir) ve klasörleri gruplar Jenkins. - Projeler iş kuyruklarını (job queue) ve bunları çalıştıracak executerları tetikler.
  • 23. Default Conf. jenkins ile gelir ve herhangi bir build aşaması için kullanılabilir. Extra Conf. kullanılan plugin tarafından isteniyor. Maven Conf. sadece maven projeleri için kullanılır. Freestyle Conf. herhangi bir proje tipi için kullanılır. create new jobs ile ilk projemizi oluştururken freestyle project tipiyle başlayabiliriz.
  • 24. Jenkins konteynırının host bilgisayarla bağlı olduğu /var/jenkins_home dizini C:Userscem.topkayaDocumentsKitematicjenkinsvarjenkins_home olarak ayarlanmış. Projemiz olan ilk project-job olsun ise host makinede “C:Userscem.topkayaDocumentsKitematicjenkinsvarjenkins_homeworkspaceilk project-job olsun” dizininde görüntülenecek. Ve doğal olarak içi boş :) Workspace Projenin “Build Now” düğmesine basıldığında sadece workspace’in silinmesi ayarı aşağıdaki Console Output ekranındaki gibi silinecek. Proje dosyalarının olduğu klasörü yani workspace’i görebiliyoruz yukarıdaki çıktıda. “/var/jenkins_home/workspace/ilk project-job olsun”
  • 27. Scripted Vs. Declarative Deklaratif ardışık düzen ile Komutlu ardışık düzen arasındaki temel fark, sözdizimleri ve esneklikleriyle ilgilidir. Deklaratif pipeline, pipeline’ı kod konsepti olarak destekleyen nispeten yeni bir özelliktir. Pipeline kodunun okunmasını ve yazılmasını kolaylaştırır. Bu kod Git gibi bir kaynak kontrol yönetim sistemine kontrol edilebilen bir Jenkinsfile içinde yazılmıştır. Oysa (Scripted) kodlanmış pipeline, kodu yazmanın geleneksel bir yoludur. Bu satırda Jenkinsfile Jenkins UI örneğine yazılır. Bu boru hatlarının her ikisi de Groovy DSL'ye dayanmasına rağmen, scripted pipeline, Groovy tabanlı daha katı sözdizimleri kullanır çünkü Groovy üzerine inşa edilen ilk pipeline idi. Bu Groovy komut dosyası genellikle kullanıcılar tarafından benimsenmediğinden, daha basit ve daha seçenekli bir Groovy sözdizimi sunmak için deklaratif ardışık düzen eklendi. Deklaratif (bildirimli) ardışık düzen, "pipeline" etiketli bir blok içinde tanımlanırken, komut dosyası verilen ardışık düzen, bir "node" içinde tanımlanır.
  • 28. Scripted Scripted pipeline, Jenkins pipeline’ı kod olarak yazmanın geleneksel bir yoludur. İdeal olarak, Scripted pipeline Jenkins web arayüzünde Jenkins dosyasında yazılır. Deklaratif düzenden farklı olarak, scripted pipeline katı bir sözdizimi kullanır. Bu nedenle, scripted pipeline kodlanmış pipeline üzerinde büyük denetim sağlar ve komut dosyasının akışını kapsamlı bir şekilde değiştirebilir. Bu, geliştiricilerin kod olarak ileri ve karmaşık boru hattı geliştirmelerine yardımcı olur. Node, Jenkins mimarisinin, node veya agent projelerin iş yükünün bir kısmını çalıştıracağı ve ana düğümün (master node) işin yapılandırmasını (configuration) işleyeceği kısmıdır. Stage bloğu görev ilerledikçe tek bir aşama veya çoklu olabilir. Ve ortak aşamaları olabilir.
  • 29. Kod güdümlü iş oluşturma Scripted - Nodes - Stages - DSL - Groovy code ● groovy kodunu kullanabilirsin ● Hata kontrolü ve raporlaması mevcut Scripted Vs. Declarative Declarative - agent - [environment] - [option] - stages - stage - [agent] - [environment] - [when] - [option] - [input] - [parameter] - steps - DSL - [post] - [failure] - [success] - [always] - [cleanup] ● Ön tanımlı kısımlar ● Kod mantığı kullanılamaz ● DSL- yönelimli kontrol ve raporlama mevcut ● Blue-Ocean uyumlu
  • 30. Parameter İster önceden ister Jenkinsfile üstünde parametreleri tanımlayalım, projeyi build ettiğimizde parametreleri görebiliriz.
  • 31. Input & Parameters & Choice Jenkinsfile (Declarative Pipeline) pipeline { agent any stages { stage('Inputlu Aşama') { input { message "Devam edelim mi?" ok "Evet lütfen :)" submitter "alice,bob" parameters { string(name: 'PERSON', defaultValue: 'Mister Rabinsın', description: 'Selamlarken buradaki değeri kullanacak') } } steps { echo "Merhaba ${PERSON}, ne güzel sizi görmek." } } } } Jenkinsfile (Declarative Pipeline) pipeline { agent any parameters { choice( choices: ['greeting' , 'silence'], description: '', name: 'REQUESTED_ACTION') } stages { stage ('Speak') { when { // Only say hello if a "greeting" is requested expression { params.REQUESTED_ACTION == 'greeting' } } steps { echo "Hello, bitwiseman!" } } } } /* * parameters ile okunan değerler strong type okunur * Yani tip parametrenin tipi Boolean ise okunan değerin * tipi de Boolean olduğu için toBoolan() ile dönüşüme * gerek kalmaz. * evironment (env.<degisken>) ise daima string döner! */ Soldaki üç türden, ilk ikisi var olmayan bir parametre talep ederseniz null döndürür - daha sonra yeni bir parametre eklemeye karar verdiğinizde ve mevcut tüm projeleri güncellemek istemediğinizde çok yardımcı olur! Ancak üçüncüsü, yapıyı çökertecektir. (${parm})
  • 32. INPUT ile Interaktif (etkileşimli) Parametre Tanımlıyoruz Durdu çünkü input bekletiyor!
  • 33. try catch pipeline { agent any triggers { GenericTrigger( genericVariables: [ [key: 'service', value: '$.service'], [key: 'image', value: '$.image'] ], token: env.JENKINS_TOKEN, causeString: 'Triggered by $image', printContributedVariables: true, printPostContent: true ) } stages { stage('Test') { steps { script { try { echo env.JENKINS_TOKEN echo service echo image } catch (Exception e) { echo "Using default images: $e.message" } } } } } }
  • 34. Agent Agent, tüm boru hattının (pipeline) veya özellikle bir aşamanın (stage) çalıştığı yerdir. Örneğin, Docker. Agent aşağıdaki parametreleri alır: ● any: tüm pipeline’ın kullanılabilir herhangi bir agent üstünde çalışacağı anlamına gelir. ● none: blok altındaki tüm aşamaların (stage) ayrı olarak agent ile bildirilmesi gerektiği anlamına gelir. ● label: sadece Jenkins ortamı için bir etiket ● docker: Docker ortamında pipeline’ı çalıştırmak içindir. Agent oluşturma başka sayfalarda anlatılacak!
  • 35. - Groovy temelli - Süreçlerin adımlarını orkestre eder - Bir pipeline script gibi job içinde veyaa repository içinde tutulan harici bir dosya olarak “Jekinsfile” adında saklanabilir Jenkins Domain Specific Language
  • 37. Yerel Makinaya Jenkins Kurulumu Bu adresten adım adım takip edebilirsiniz. - Bu adresten war dosyasını indir - konsoldan şu komutu çalıştır - java -jar jenkins.war --httpPort=8080 - internet gezgininden http://localhost:8080 adresini aç jenkins.war çalıştırıldığında $user.home/.jenkins dizinini oluşturmak ister. Hızlıca çalıştırmak için oluşturduğumuz run.bat dosyası çalışıp uygulama ayaklandığında %USERPROFILE%.jenkins klasörü oluşur ve pluginler bu klasöre yüklenir. Farklı bir dizinde .jenkins klasörünü barındırmak istersek ortam değişkenlerinden JENKINS_HOME anahtarına istediğimiz yeni dizinin adresini girip .jenkins dizininin içeriğini taşıyabiliriz.
  • 38. Jenkins’i Farklı Dizinde Çalıştırmak
  • 39. Hangi Komut Satırı? İleride çalıştıracağımız “echo cem” işleminin çıktılarını sağ tarafta incelediğimizde; jenkins’in docker yansısı - eğer linux ise, echo işlemini /bin/sh üstünde çalıştırmakta, - windows ise cmd üstünde koşturmakta Host olarak hangi işletim sistemi koşuyorsa buna uygun command yazmamız veya docker yansısını komutlarımıza göre seçmemiz gerek. Linux host üstünde koşan Jenkins için sh ile çalışıyorken bat ile komutlarımızı çalıştırıyoruz.
  • 41. Master Agent Node Birinci ve yöneten Jenkins düğümünün kurulumu
  • 42. Hangi Docker Yansısı? Birinci Jenkins düğümü için (eskiden master derdik) jenkins/jenkins yansısını kullanabilirken, ikinci yahut işçi jenkins ajanları için jenkins/slave yansısını kullabiliriz (slave de yakında kaldırılır). $ docker pull jenkins/jenkins Not: jenkins ve jenkinsci/jenkins yansıları kullanımdan kaldırıldı. $ docker pull jenkins/slave
  • 43. Docker ile Master Jenkins Kurulumu - 1 Jenkins docker görüntünüzün (image) içinde docker görüntüleri (images) oluşturmayı planlamıyorsanız, örneğimdeki --privileged bayrağını göz ardı edebilirsiniz. Reverse proxy olarak nginx çalıştırmak istersek, nginx dosyasının default.conf içeriği: upstream app { server 127.0.0.1:49001; } server { listen 80; server_name hosts_a_ne_yazarsan; location / { proxy_pass http://app; } } $ docker pull jenkins $ docker run --detach --publish 49001:8080 --volume $PWD/jenkins:/var/jenkins_home --tty --privileged --restart=always jenkins/jenkins
  • 44. Docker ile Master Jenkins Kurulumu - 2 Docker ile ister komut satırından ister kitematic ile jenkins/jenkins isimli docker yansısını yükleyebiliriz. Kurulum sonrasında docker attach <container-id> ile container konsol ekranında neler olduğunu görebiliriz. Komut satırında -d anahtarı olmada çalıştırırsak jenkins ön planda çalışır ve işletilen komutların çıktılarını yani jenkins processinin I/O çıktılarını kullandığımız konsol üstünde görebiliriz. Ama -d anahtarını kullanırsak bu bilgileri görmek için docker attach <container-name> komutunu çalıştırmamız gerekir.
  • 45. Slave Agent Node Sonraki Jenkins ajan düğümlerinin kurulumu
  • 46. Docker ile Slave Jenkins Kurulumu docker run --interactive --rm --name agent --init -v c:/Temp/Jenkins:/home/jenkins/agent jenkins/agent java -jar /usr/share/jenkins/agent.jar -workDir /home/jenkins/agent
  • 47. Slave Jenkins Ajanı Üstünde İş Çalıştırmak dpipeline { agent { label 'ajan' } stages { stage('Test') { steps { sh 'pwd' } } } }
  • 48. Jenkins Terminali Root İle Kullanmak Konteyner ile terminal bağlantısı kurmak istediğimizde --user root argümanı eklersek root yetkisiyle bash’e bağlanabiliriz. root Kullanıcısıyla apt işlemlerini yapabilir ve sistem seviyesinde nodejs kurulumu sağlarız. -- privileged Argümanı da root ile bağlanmamızı sağlar. Not: Resimde gördüğünüz gibi root yetkisi olmadan :/$ ile diğer kullanıcılar için :/# ile terminale bağlanıyoruz. - Dolar işareti ($), normal bir kullanıcı olduğunuz anlamına gelir. - hash (#), sistem yöneticisi (root) olduğunuz anlamına gelir. - C kabuğunda, komut satırı yüzde işaretiyle (%) biter. roo@1ee9eb95c6bb:/$ <Kullanıcı Adı>@<makine adı>:<geçerli dizin><[$,#]> Kullanıcı Adı: Bu örnekte root -veya- jenkins görünür. Oturum açtığınız kullanıcı hesabını anlarız. Makine Adı: Makine ana bilgisayar adı. İçinde bulunduğumuz makine adıdır. Docker için kabın ID değeridir (1ee9eb95c6bb). Geçerli Çalışma Dizini: Bağlandığımız makinede içinde bulunduğunuz dizini gösterir. / : Öne doğru eğik çizgi (/) Kök dizinini işaret eder. “cd /” komutuyla hızlıca kök dizine gidilebilir. ~ : Tilde işareti ana dizin anlamına gelir, yani ilk oturum açarken varsayılan dizin. jenkins kullanıcısı oturum açtığında “jenkins@d7d9d29b565f:~$” dizinine düşer. Buradaki tilde işareti “/var/jenkins_home” dizinini işaret eder.
  • 49. Jenkins’in Varsayılan Dilini Değiştirmek Özetle: - Locale eklentisini indir - Jenkins -> Ayarlar/Configuration Kısmında “Varsayılan Dil” yerine istediğiniz dili kısa koduyla yazın (tr, en, fr gibi) - İnternet gezgininizin diliyle görüntülenmemesi için altındaki “ignore browser preference..” seçilir
  • 50. Docker ile Master Jenkins Kurulumu - 3 Jenkins’in Şifresi Kurulum sırasında jenkins ilk giriş için bir şifre oluşturacak ve bunu konsolumuza yazacak. jenkins_home Dizinini bağladığınız kendi diskinizdeki klasörü silerseniz ve jenkins tekrar kurulurken yine aynı konsolu göreceksiniz. Eğer burayı kaçırırsanız docker stop <container-name> ile konteynerınızı durdurup başka bir konsol ekranından docker attach <container-name|id> ile birazdan açacağınız docker container konsolunu takip edebilirsiniz. Tekrar docker start <container-name> ile başlatırken attach olduğunu konsolda gizli anahtarı görebilirsiniz.
  • 52. NodeJs Kurulumu - 1 Konteyner ile terminal bağlantısı kurmak istediğimizde --user root argümanı eklersek root yetkisiyle bash’e bağlanabiliriz. root Kullanıcısıyla apt işlemlerini yapabilir ve sistem seviyesinde nodejs kurulumu sağlarız. Not: Resimde gördüğünüz gibi root yetkisi olmadan :/$ ile diğer türlü :/# ile terminale düşüyoruz. NodeJs kurulumu için paket listesini güncelleyelim ve sistem üstünde nodejs kurulumu yapalım ve sonunda node ve npm versiyonunu görüntüleyelim: apt-get update && apt-get upgrade -y && curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs && node --version && npm --version Çıktımız:
  • 53. Jenkins “NodeJS Plugin” eklentisiyle (plugin) nodejs çalıştırabilir. Bu eklentiyle Nodejs’in farklı sürümlerini araç olarak (tools) kurabilir ve job içinde shell için PATH’e kaydeder ve npm, node uygulamalarını çalıştırabilirsiniz. NodeJs Kurulumu -2 Sistemde kurulu bir nodejs varsa PATH içinde kurulu NodeJS uygulamasının bin dizini içindeki “node” uygulamasına herhangi bir shell içinden erişilebilir. Bu en genel ve temiz çözümdür. Ama sisteme NodeJS kurma yetkiniz yok ve sadece Jenkins’i yönetiyorsanız NodeJS Plugin ile uygun versiyonu seçerek /var/jenkins_home/tools/nodejs. . içinden kullanabilirsiniz. pipeline { agent any // tools’la içeri alıp kullanıyoruz tools {nodejs "node_14.14.0"} stages { stage('Example') { steps { sh 'npm config ls' } } } }
  • 54. NodeJS İçin Tools Arka Planda Ne Yapar? NodeJS eklentisi kurulduktan sonra Manage Jenkins > Global Tool Configuration içinde hangi NodeJS sürümlerini kullanmak istiyorsanız bir etiketle tanımını yaparsınız. Yandaki örnekte 3 farklı sürüm için 3 etiket tanımlanmış. Hangisi job içinde kullanılırsa o sürüm /var/jenkins_home/tools içine indirilir ve shell içinden erişilebilmesi için geçici PATH içinde tanımlanır. Böylece node veya npm çağrısı yapıldığında NodeJS uygulamalarına erişilebilinir.
  • 55. Önce terminal ekranına giriş yapalım: Paket listesini güncelleyip node kurulumu yapalım ve unutmayalım setup_8.x deprecate olduğu için yerine 10 veya 12 kurmak daha iyi olacaktır: Ve son çıktı: Jenkins Konteyner İçine NodeJS Kurulumu
  • 57. Docker Konteyner İçinde Jenkins Slave Çalıştırmak docker run -i --rm --name agent --init jenkins/agent java -jar /usr/share/jenkins/agent.jar -i : Keep STDIN open even if not attached --rm: Docker automatically clean up the container and remove the file system when the container exits --init : konteyner başlatıldığında çalıştırılsın diye girdiğimiz komutu PID 1 olacak şekilde başlat. Yani init process olarak başlat. -v : (Volume Binding) Host makinamızdaki dizinleri konteynere bağlıyoruz. --rm ile başlattığımız için konteyner durduğunda içinde yaptığımız her şey silinecek bu yüzden host makinamızdaki dizinleri bağlayarak her docker slave başlatıldığında windows makinamızdaki ssh anahtarları, calisma dizinleri vs. docker konteynere bağlanacak. $ docker run -i --rm --cpuset-cpus="0-3" --name agent -v /c/Users/cem.topkaya/.ssh:/root/.ssh -v /c/Us../git/calismalar:/home/jenkins/calismalar -v /c/User..lar/home_jenkins_agent:/home/jenkins/agent --init cemkins/agent
  • 59. Git’i Tanıtalım whereis git diyerek konteyner içinde git’in yerini buluruz ve node üstünde Tool Locations içine git’in dosya yolunu gireriz, hepsi bu. 1 2
  • 60. Diskimizi Bağlayalım 1 2 docker run -i --rm --name agent -v /c/Users/cem.topkaya/git/calismalar:/home/jenkins/calismalar -v /c/Users/cem.topkaya/git/calismalar/home_jenkins_agent:/home/jenkins/agent --init jenkins/agent java -jar /usr/share/jenkins/agent.jar 3 4
  • 61. whereis npm whereis npm ile node yüklenmediğini görürüz. Sunum dosyasında node kurulumuyla ilgili komutlar konteynerin konsoluna bağlanarak çalıştırabiliriz. Ancak unutmayalımki node yüklemesini konteyner içine yapıyoruz ve eğer --rm anahtarıyla başlattığımız konteyner, görevi bitince kaldırılır ve yeni konteyner başlattığımızda yine node kurulumu gerekir. Veya jenkins/agent yansısını miras alarak içinde node yüklü yeni bir yansı yaratabiliriz. FROM jenkins/agent USER root RUN apt-get update && apt-get upgrade -y && curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs && node --version && npm --version EXPOSE 22 80 USER jenkins CMD java -jar "/usr/share/jenkins/agent.jar" #ENTRYPOINT java -jar "/usr/share/jenkins/agent.jar"
  • 63. Jenkins Admin Kullanıcısı Oluşturmak İlk ekrana girdiğiniz gizli kelimeden sonra önerilen pluginleri kurar ve ardından kullanıcı tanımlarsınız. Ve artık jenkins hizmetinize sizin tayin ettiğiniz (örn. 8080) porttan başlatılır.
  • 65. JDK Linux üstünde $ which javac ile JDK dizininin yolunu öğrenebilir ve Global Tool Configuration içinde tanımlayabiliriz.
  • 66. Git Linux üstünde $ which git ile GİT dizininin yolunu öğrenebilir ve Global Tool Configuration içinde tanımlayabiliriz.
  • 67. NodeJS Linux üstünde $ which node ile Node dizininin yolunu öğrenebilir ve Global Tool Configuration içinde tanımlayabiliriz.
  • 69. Github Authentication Bilgisayarınızda lokalde çalışan bir jenkins olsun. Kodlarınızı barındırdığınız git adresini projenizin Source Code Management sekmesine girdiniz. Jenkins arka tarafta HEAD metoduyla ilgili adrese bir istek yapacak. Eğer kullanıcı bilgileriniz geçerli değilse yandaki hatayı verecek. Failed to connect to repository : Command "git.exe ls-remote -h -- https://github.com/cemtopkaya/angular-module.git HEAD" returned status code 128: stdout: stderr: Logon failed, use ctrl+c to cancel basic credential prompt. remote: Invalid username or password. fatal: Authentication failed for 'https://github.com/cemtopkaya/angular-module.git/' Bu durumda artık github için bir kullanıcı doğrulama yöntemi seçerek devam etmeliyiz. - Windows Kimlik Yöneticisinde kullanıcı bilgilerinin depolanması - Username ve Password ikilisi olan credential - Github Token kullanmak
  • 70. Kullanıcı Bilgileri Yöneticisi Konsol üstünden github reposunun clone ile çekilmesi sağlandığında Windows Kimlik Bilgileri Yöneticisi kullanıcı bilgilerini depolayacak ve eğer Credentials açılır kutusundan bir seçim yapılmamışsa, Jenkins her github için arka planda yapacağı istekte sistemde kayıtlı olan bu bilgileri kullanacak. Github için yapılacak istek başarısızsa aşağıdaki gibi, başarılıysa boş gövdeli cevap döner:
  • 71. Github Kullanıcı Adı & Şifresi Sistemde kayıtlı kullanıcı bilgileri yerine belirlediğimiz credential ile bağlanmak istediğimiz durumdur. Github reposunu yazdığımız yerde Add düğmesiyle (veya Jenkins Credential menüsünden) Username with Password tipinde bir tanımlama yaparız. Kullanıcı adı ve şifresiyle bir credential oluşturup projenin Source Code Management sekmesinde Credentials açılır kutusunda seçili hale getirebiliriz.
  • 72. Github Token ile Webhook (1) Github üstünden bir Token yaratıp Jenkins içinde yeni bir Credential olarak tanımlarız. (2) Bu kez Jenkins’in tüm projeleri tarafından kullanılabilecek şekilde token bilgisini ayarlayacağız Manage Jenkins / Configure System / Github içinde az önce oluşturduğumuz TOKEN seçilerek Github server ile webhook için kullanılacak token ayarlanır. Oluşturduğumuz token’ın testi için curl -u username:token https://api.github.com/user komutunu konsoldan çalıştırabiliriz.
  • 73. Github Ayarı Github üstündeki bir repoya bağlanmak istersek github sunucu ayarlarına hangi token ile bağlanacağımızı söylememiz gerekiyor. Sonrasında projemizin General ayarlarında bu projenin bir Github projesi olduğunu seçmeli ve Source Code Management içinde git seçeneğini işaretleyip hangi adresten veri çekeceksek projenin bağlı olduğu github kaynak kodunun adresini ve hangi branch üstünde koşacağımızı belirtmeliyiz. Build ettiğimizde kodun indiğini görürüz.
  • 74. Github Public Repo Ayarı Projenin (burada ng_form adında freestyle tipinde), Configure sekmesinden Source Code Management kısmında Git seçilip, clone yapmak için kullandığımız adresini yapıştıralım. Projeyi build ettiğimizde kodlar çekilerek workspace içine dosyalarımız konulacak. 1 2 3 4 5
  • 75. Github Private Repo Ayarı Önce kayıtlı şifreyi silelim ki; github üstünde private repomuza giderken şifre sorulur hale gelsin ve yerelde çalışan jenkins için de şifre istensin. Böylece Github token yaratma yoluna gidelim. git config --global credential.helper store ile kullanıcı adı ve şifresini bilgisayara depolayacağız demiş oluruz. Kullanıcı adı ve şifresini ilk girdiğimiz anda önce %USERPROFILE.git-credentials dosyasına https://gitKullaniciAdi:gitSifresi@github.com bilgisi yazılır ardından Windows Kimlik Bilgileri Yöneticisi bu bilgileri ön bellekler. Eğer Windows Kimlik Bilgileri Yöneticisi üstünden siler tekrar git clone ile yerele kodları çekmek istediğimizde kullanıcı bilgileri WinKimlikBilgYöneticisi üstünden okunmak istenir, bulunamayınca .git- credentials dosyasından veriler okunur ve WinKimlikBilgYöneticisi üstüne tekrar yazılır. Bir sonraki clone işleminde WinKimlikBilgYöneticisi kullanıcı bilgilerini servis eder ve .git-credentials dosyasına gerek kalmadan kullanıcı girişi sağlanmış olur.
  • 76. Kullanıcı Bilgileri Sırası 1. Windows Kimlik Bilgileri Yöneticisi 2. .git-credential 3. cache
  • 78. sh(''' git config user.name 'my-ci-user' git config user.email 'my-ci-user@users.noreply.github.example.com' ''') withCredentials([usernamePassword(credentialsId: 'my-credentials-id', usernameVariable: 'GIT_USERNAME', passwordVariable: 'GIT_PASSWORD')]){ sh(''' git config --local credential.helper "!f() { echo username=$GIT_USERNAME; echo password=$GIT_PASSWORD; }; f" git push origin HEAD:$TARGET_BRANCH ''') } stage('Push') { environment { GIT_AUTH = credentials('my-predefined-credentials-id') } steps { sh(''' git config --local credential.helper "!f() { echo username=$GIT_AUTH_USR; echo password=$GIT_AUTH_PSW; }; f" git push origin HEAD:$TARGET_BRANCH ''') } } Push via HTTPS Push via HTTPS git branch: 'dev', credentialsId: 'cred_id_bitbuket_icin', url: 'https://jenkins.kullanici@bitbucket.com/scm/cin/gui_test.git' git checkout -B $TARGET_BRANCH Checkout
  • 79. pipeline { agent any stages { stage("Build") { steps { // Create a dummy file in the repo sh('echo $BUILD_NUMBER > example-$BUILD_NUMBER.md') } } stage("Commit") { steps { sh(''' git checkout -B $TARGET_BRANCH git config user.name 'my-ci-user' git config user.email 'my-ci-user@users.noreply.github.example.com' git add . && git commit -am "[Jenkins CI] Add build file" ''') } } stage("Push") { environment { GIT_AUTH = credentials('support-team-up') } steps { sh(''' git config --local credential.helper "!f() { echo username=$GIT_AUTH_USR; echo password=$GIT_AUTH_PSW; }; f" git push origin HEAD:$TARGET_BRANCH ''') } } } }
  • 80. pipeline { agent any stages { stage("Tag and Push") { when { branch 'master' } environment { GIT_TAG = "jenkins-$BUILD_NUMBER" } steps { sh(''' git config user.name 'my-ci-user' git config user.email 'my-ci-user@users.noreply.github.example.com' git tag -a $GIT_TAG -m "[Jenkins CI] New Tag" ''') sshagent(['my-ssh-credentials-id']) { sh(""" #!/usr/bin/env bash set +x export GIT_SSH_COMMAND="ssh -oStrictHostKeyChecking=no" git push origin $GIT_TAG """) } } } } }
  • 82. Sıralı Olarak Projeleri Build Etmek 1. Görevi build ettiğimizde konsol çıktısında 2.nin sıraya girdiğini yazar. Aynı şekilde ana ekranda “Build Queue” kısmında da sıradaki görevleri görebiliriz.
  • 83. Delivery Pipeline İle Görselleştirme 1 2 3
  • 85.
  • 86. Gerekenler - VirtualBox veya VMware Player kurula - En hafifinden linux kurulu bir disk indirilip sanal makine (virtual machine) çalıştırıla - Sanal makine içine java kurula - openssh-server linux içine kurulup dışarıdan erişilebilir hale getirile - jenkins içinde yeni vm’in bilgileriyle bir node/agent oluşturula
  • 87. Sanal Linux Kurulumu https://www.osboxes.org/linux-lite/ Adresinden linux kurulu disk indirilerek VirtualBox üstüne eklenir. Hemen “passwd” komutuyla osboxes.org kullanıcısı, “sudo passwd root” ile root şifresi değiştirilir.
  • 88. VirtualBox Ağ Ayarları VirtualBox üstünde 3 ağ tanımlı. Sanal makinamızın 1. ağ bağdaştırıcı NAT ile internete bağlanması için iken 2. ağ bağdaştırıcı host ile doğrudan bağlantı kurması için. Not: Farklı ayarlar da yapılabilir
  • 89. Linux Ağ Ayarları nmtui kullanıcı arayüzü, dhclient veya ifconfig ile ağ işlemlerini yapabiliriz Ağ Ayarlarını Görüntülemek DHCP Sunucusuna “merhaba” gönderip iletişimi görelim $ dhclient -v $ ifconfig -a Ağ Ayarlarını Tazelemek $ sudo dhclient -v -r $ ifconfig ağ_adı down $ ifdown ağ_adı $ ifconfig ağ_adı up $ ifup ağ_adı Ağ Servisini Yeniden Başlatmak $ /etc/init.d/nscd restart
  • 90. Sadece Openjdk’yı kaldırmak istiyorsak: $ sudo apt-get remove openjdk* Openjdk’yı tüm bağımlılıklarıyla kaldırmak istiyorsak: $ sudo apt-get remove --auto-remove openjdk* Openjdk ve ayar dosyalarını kaldırmak istiyorsak: $ sudo apt-get purge openjdk* Openjdk, bağımlılıkları ve ayar dosyalarını kaldırmak istiyorsak: $ sudo apt-get purge --auto-remove openjdk* Java Yüklemek & Kaldırmak Repoyu güncelleyerek java indirebileceğimiz adresleri çekeriz: $ apt-get update $ apt install oracle-java11-installer $ apt install default-jre $ apt install openjdk-11-jre-headless $ apt install openjdk-8-jre-headless $ apt install openjdk-8-jdk-headless Sadece openjdk-8-jdk-headless paketinin kurulması hem java hem javac için yeterli olacaktır. Sürüm Kontrolü java Runtime (JRE) : $ java -version Java Development Kit (JDK): $ javac -version
  • 91. Yeni Kullanıcı Tanımlamak Master olan Jenkins projelerin tanımlandığı, ayarlarının yapılıp yapılandırmak için tetiklendiği ve çıktıların gözlemlendiği ilk kurulumumuzdur. Diğer sunucular (node/agent’lar) ise agent.jar isimli dosyanın sürekli çalışıp master jenkins tarafından gelen işlerin yapıldığı düğümlerdir. Bu düğümlere job’ların yüklenmesi için bir kullanıcı tanımlanır ve master jenkins, ssh marifetiyle bağlanarak ilgili agent.jar dosyasını yükler ve çalıştırır. agent.jar Dosyası tabiatı gereği Java kurulumu da gerektirdiği için önceden yüklenmiş olması gerekir. Kullanıcı Silmek Silinmek istenen kullanıcı aktif bir processleri killall ile durdurulur veya zorla (force) silmek istediğimizi -f argümanı ile veririz. $ killall -u kullanıcı_adı $ userdel -f --remove-home kullanıcı_adı Yeni Kullanıcı Oluşturmak $ useradd -m cemkins Yeni Kullanıcıya Şifre Atamak cemkins kullanıcısının yeni şifresini iki kez girilir ve yeni kullanıcıyla sisteme giriş yapılar. $ passwd cemkins Yeni Kullanıcı Profilinde Jenkinse Özel Dizin Oluşturmak Yeni kullanıcının profili /home/kullanıcıAdı dizininde oluşacaktır. Jenkins bu klasörün altına remote.jar dosyası ve remote dizini oluşturacağı için derli toplu olsun diye biz jenkinsKokDizini diye bir klasör oluşturalım. $ mkdir jenkinsKokDizini
  • 92. SSH Kurulumu ssh Server Kurulur $ sudo apt-get install openssh-server ssh Servisi Faal Edilir $ sudo systemctl enable ssh ssh Servisi Başlatılır $ sudo systemctl start ssh Servisin Durumu Kontrol Edilir $ sudo systemctl status ssh ssh Bağlantısı Test Edilir $ ssh root@makina-adı|ip Dışarıdan Bağlanmak İçin Ayar Yapılandırılır # ile başlayan satırlar yorum satırı demektir. Bazı komutların yorum satırı olmadığı belirtmemiz gerekecek: $ vi /etc/ssh/sshd_config #PermitRootLogin prohibit-password satırı aşağıdaki hale getirilir PermitRootLogin yes #PasswordAuthentication yes yorum satırı olmaktan çıkarılır PasswordAuthentication yes Eğer ssh key ile giriş yapılabilsin istiyorsak aşağıdaki satırlar yorum satırı olmaktan çıkarılır #PubkeyAuthentication yes #AuthorizedKeysFile .ssh/authorized_keys ssh Secure Shell anlamıa gelir ve telnetin şifrelenmiş halidir. sshd ise servis (daemon) halinde çalışan ssh sunucusudur. sshd_config içinde yapılan değişikliklerin etkili olması için servisin tekrar başlatılması gerekir.
  • 93. ssh Sorun Giderme SSH bağlantısı sırasında “Host key verification failed.*” hatası alınırsa, bağlantı kurulacak makina için “bilinen hostlar” dosyasında güncelleme yapmak için $ ssh-keygen -R 192.168.99.102 komutu çalıştırılır. IP adresi, bağlantı kurmak istediğiniz uzak makinanın adresi veya ismidir. known_hosts dosyası .ssh dizini altındadır. $ ssh-keygen -R <ip | host_adı> Komutuyla her uzak bağlantı için bir key üreterek güvenilir bağlantılar listesine ekler. SSH servisini otomatik üretiyorduk ve diyelimki ayarlar dosyası çalışmaz hale geldi ve aşağıdaki hatayı almaya başladık: Unit sshd.service could not be found Tüm openssh-server’ı kaldırmak yerine konfigurasyon dosyalarını kaldırıp tekrar kurulum yapmak yeterli olacaktır. $ apt-get purge openssh-server $ apt-get install openssh-server Elbette tüm ssh server’ın kaldırılıp tekrar kurulmasında da sakınca yok $ apt-get remove --purge openssh-server $ apt-get install openssh-server $ service ssh restart $ service ssh status
  • 94. Docker Jenkins İçin Plug-In Kurulumunda Hata Docker versiyonu jenkins/jenkins yansısını kullanıyor ve plugin güncellemesi yapamadığını görüyorsanız jenkinsin pluginleri indirebileceği adresi ortam değişkeni olarak jenkins kabınıza vermeniz gerekiyor. Bunu 3 farklı adresi verip deneyebilirsiniz: 1. http://ftp-nyc.osuosl.org/pub/jenkins 2. http://mirrors.jenkins-ci.org 3. https://updates.jenkins.io/download/plugins Kitematik ile veya docker kabınızı çalıştırırken yapabilirsiniz docker run --name jenkinscim .... -e JENKINS_UC_DOWNLOAD 'http://ftp- nyc.osuosl.org/pub/jenkins' jenkins/jenkins
  • 95. Agent Launch Sorun Giderme Slave node üstünde ssh kurulu ancak java yok! > Java kurulur ve tekrar denenir. Checking java version of /home/cemkins/jenkins_kok_dizini/jdk/bin/java Couldn't figure out the Java version of /home/cemkins/jenkins_kok_dizini/jdk/bin/java bash: /home/cemkins/jenkins_kok_dizini/jdk/bin/java: No such file or directory Çalıştırmak istediği komuş aşağıda göreceğiniz üzere remoting.jar dosyasını ayaklandırarak master üstünden slave ile konuşabileceği bir iletişim kanalı açmak: [SSH] Starting agent process: cd "/home/cemkins/jenkins_kok_dizini" && /usr/bin/java -jar remoting.jar -workDir /home/cemkins/jenkins_kok_dizini - jar-cache /home/cemkins/jenkins_kok_dizini/remoting/jarCache - Yukarıdan anlayacağınız üzere /usr/bin/java ile çalıştırılabilir java dosyasına erişmek ve -jar argümanı ile remoting.jar dosyasını ayaklandırmak istediğini söyleyecek. - remoting.jar dosyasına çalışılacak dizini ve -jar-cache ile ön bellek dizinini vermek istiyor Java yolunu öğrenmek için $ whereis java konsola yazılır ve uygun dosya yolu bulunur ve Advanced düğmesiyle açılan bölümde JavaPath etiketli alana java’nın yolu yazılır. Not: Eğer yüklü değilse java yükleme kısmına bakabilirsiniz.
  • 97. Jenkins çeşitli formlarda saklanabilen tüm credential bilgilerini Credentials menüsünde saklıyor. Node tanımında login olacağımız linux makinasındaki cemkins kullanıcısının bilgilerini Credentials satırında Add düğmesiyle(1) açılan ekranda(2) tanımlıyoruz. SSH yaptığımızda, sunucu makine /etc/ssh içinde tanımlı kendi HOST KEY’ini gönderir, SSH istemci makinesi ise known_hosts dosyasında bu anahtarı bulursa bağlantı kurulur. Bulamazsa uzak makinenin HOST KEY bilgisini known_hosts dosyasına eklemek istermiyiz diye sorar. Böylece daha sonraki bağlantılarda ssh server doğrulanır. 1 3 2
  • 98.
  • 100. Private Registry # docker tag alpine:latest localhost:5000/malpine # docker push localhost:5000/malpine The push refers to repository [localhost:5000/malpine] beee9f30bc1f: Pushed latest: digest: sha256:cb8a92...b8d221 size: 528 # curl http://localhost:5000/v2/_catalog {"repositories":["malpine"]} Private Registry Kurulumu $ docker run -d -p 5000:5000 --restart always --name registry registry:2 https://docs.docker.com/registry/spec/api/ # curl http://localhost:5000/V2/_catalog # curl http://localhost:5000/v2/<name>/tags/list DELETE /v2/<name>/manifests/<reference>
  • 102. Sadece openssh-server’ı kaldırmak istiyorsak: $ sudo apt-get remove openssh* openssh-server’ı tüm bağımlılıklarıyla kaldırmak istiyorsak: $ sudo apt-get remove --auto-remove openssh* openssh-server ve ayar dosyalarını kaldırmak istiyorsak: $ sudo apt-get purge openssh* openssh-server, bağımlılıkları ve ayar dosyalarını kaldırmak istiyorsak: $ sudo apt-get purge --auto-remove openssh* openssh-server Yüklemek & Kaldırmak $ apt-get update $ apt-get install openssh-server
  • 103. openssh-server Kurulum Detayları $ apt-get install openssh-server … The following additional packages will be installed: openssh-sftp-server ssh-import-id Suggested packages: molly-guard monkeysphere rssh ssh-askpass The following NEW packages will be installed: openssh-server openssh-sftp-server ssh-import-id ...Fetched 389 kB ...Unpacking openssh-sftp-server … Preparing to unpack .../openssh-server_1%3a7.6p1-4ubuntu0.3_amd64.deb ... ...Preparing to unpack .../ssh-import-id_5.7-0ubuntu1.1_all.deb ... ...Creating config file /etc/ssh/sshd_config with new version ...Creating SSH2 RSA key; this may take some time ... 2048 SHA256:Fy/9w38/BzTJCVEdu7czKDg5DcwHSrQT/2/fpTnHufc root@osboxes (RSA) Creating SSH2 ECDSA key; this may take some time ... 256 SHA256:oZaVFTz0Eh4PtY4pTFkoAjlcjoqb+YJJppDLtQiUtl8 root@osboxes (ECDSA) Creating SSH2 ED25519 key; this may take some time ... 256 SHA256:TSmPKhMlzRDys5GQSK9mC8fLaRmDEO7dIlLLGdZDPAw root@osboxes... Created symlink /etc/systemd/system/sshd.service → /lib/systemd/system/ssh.service. Created symlink /etc/systemd/system/multi-user.target.wants/ssh.service → /lib/systemd/system/ssh.service. ...Processing triggers for systemd (237-3ubuntu10.39) ...
  • 105. ssh Anahtarları Oluşturmak ve Kullanıma Açmak 1) SSH Anahatarı Oluşturmak: ssh-keygen komutu çalıştırıldığında, yeni ssh anahtarının adını soracak. - Eğer enter ile geçersek $HOME dizini içinde .ssh klasörünü ve içerisine id_rsa dosyasını gizli anahtarı (private key), id_rsa.pub dosyasını da public anahtarı saklayacak şekilde oluşturur. - Eğer bir dosya adı girersek bu kez $HOME dizini içinde dosyaAdi adında private, dosyaAdi.pub adında public anahtarları oluşturur. - Mesela github’a bağlanmak için bir ssh anahtarı yaratıyor olalım ve dosya adına github_cemtopkaya diyelim. Bu durumda $HOME/github_cemtopkaya ve $HOME/github_cemtopkaya.pub adında private ve public anahtarları oluşturacak. Tabi bu dosyaları şifreleyecek ve sadece bizim bileceğimiz bir passphrase (parola) girmemizi iki kez istedikten sonra dosyalar oluşturulmuş olacak. $ ssh-keygen -t rsa -b 4096 -C "cem.topkaya@hotmail.com" 2) SSH Agent’a SSH Anahtarlarını Kaydetmek: ssh-keygen komutuyla oluşan anahtarları ssh-agent üstüne kaydederek kullanıma sunmalıyız. Ama önce ssh-agent çalışıyor mu diye bakalım. $ eval "$(ssh-agent -s)" Şimdi ürettiğimiz anahtarları ekleyeceğiz. Örneğin github, gitlab ve bitbucket için farklı public ve private anahtarlar üretmiş olalım ve hepsini bir kerede ekleyelim. $ ssh-add github_cemtopkaya bbCemTopkaya .ssh/id_rsa $ sudo -su giris_yapilan_kullanici_adi $ ssh-keygen -t rsa -b 4096 -C "cem.topkaya@hotmail.com" $ eval "$(ssh-agent -s)" $ ssh-add github_cemtopkaya bbCemTopkaya .ssh/id_rsa
  • 106. Github & Jenkins SSH Anahtar Ayarları Jenkins üstünde Global Credential oluşturuyoruz. - SSH Username with private key seçeneğiyle - Username ile bağlanacağımız sistemin kullanıcı adı, - ID bilgisini biz yazarsak anlamlı ve eşsiz bir tanımlama, boş bırakırsak UUID değer atanır, - Private Key kısmına bir önceki sayfada hazırladığımız SSH anahtarının private kısmını yapıştırırız. Böylece Jenkins privte anahtar içeren dosyayı aramak, dosya yoluna bağlı kalmak zorunda olmayacaktır. - Passphrase ise ssh-keygen ile SSH anahtarını oluştururken bize gizli bir parola girmemizi istediğinde yazdığımız metin. Github üstünden kişisel ayarlardan SSH and GPG keys sekmesinde ise Key kısmına SSH anahtarımızın public anahtarının içeriğini yapıştırıyoruz ve tanımlama için title alanına ayrıştırılabilir bir metin girilir.
  • 108. Jenkins üstünde oluşturduğumuz “SSH Username with private key” türündeki credential’ı kullanabileceğimiz GİT SCM Reposuna SSH ile bağlantı kurmamız gerekiyor. Freestyle Projede https & SSH Git Repo Bağlantısı
  • 109. Jenkins üstünde oluşturduğumuz “SSH Username with private key” türündeki credential’ı kullanabileceğimiz GİT SCM Reposuna SSH ile bağlantı kurmamız gerekiyor. Pipeline Projede Https & SSH Git Repo Bağlantısı git( url: 'ssh://git@bitbucket.org:company/repo.git', credentialsId: 'xpc', branch: "${branch}" ) git branch: params.SOURCE_BRANCH_NAME, credentialsId: params.GIT_HTTP_CRED_ID, url: params.GIT_REPO_ADDR_HTTP checkout([ $class: 'GitSCM', branches: scm.branches, doGenerateSubmoduleConfigurations: false, extensions: scm.extensions + [[ $class: 'SubmoduleOption', disableSubmodules: false, recursiveSubmodules: true, reference: '', trackingSubmodules: false ]], submoduleCfg: [], userRemoteConfigs: scm.userRemoteConfigs ]) withCredentials([ usernamePassword( credentialsId: your_credentials, passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) { sh "git tag ${your_tag}" sh "git push https://${GIT_USERNAME}:${GIT_PASSWORD}@${repo} ${tag}" } sshagent ( ['a-jenkins-credential']) { sh ''' ssh -vv myuser@myserver echo testing connection || true ssh-add -L echo done running remote windows test ''' }
  • 113. Linux Mint 19.2C Sürümü https://sourceforge.net/projects/osboxes/files/v/vb/31-Lx-M-t/19.2/Cinnamon/19-2C-64bit.7z/download 1) Uygulama Havuzunu Güncellemek $ sudo apt update 2) Snap İle Jenkins Kurmak $ sudo apt install snapd 3) Snap İle Daha Önce Kurulu Jenkins’i Güncellemek $ sudo snap refresh jenkins --classic 4) Jenkins Servisinin Durumunu Görmek $ systemctl status snap.jenkins.jenkins.status 5) Jenkins Servisi Durmuşsa Başlatmak $ systemctl start snap.jenkins.jenkins.status 6) Jenkins Servisi Çalışıyorsa Browser Üstünde Görüntülemek $ xdg-open http://localhost:8080 Bir Browser Aç Adres Satırına Şunu yaz: http://localhost:8080 7) Git Kurmak $ sudo apt install git 8) JDK Kurmak $ sudo apt install openjdk-8-jdk-headless 9) SSH Server (jenkinse ssh ile uzak bağlantı için) $ sudo apt install openssh-server Jenkins $ Jenkins $ Jenkins $
  • 115. Veri Tipleri ● Simple data types ○ Strings ○ Numbers ○ Regular expressions ○ Booleans ○ Arrays ● Collections ○ List ○ Set ○ Maps ○ Ranges
  • 116. Başlıklar groovy-net groovy-xml groovy-string groovy-number groovy-html groovy-date groovy-collections
  • 117. String Java'da olduğu gibi, karakter verileri çoğunlukla java.lang.String sınıfı kullanılarak işlenir. Groovy strings iki çeşittir: - plain strings, - GStrings. Düz dizeler java.lang.String ve GStrings ise groovy.lang.GString örnekleridir. GStrings, ifadeleri (genellikle birçok komut dosyası dilinde dize enterpolasyonu olarak adlandırılır) çalışma zamanında çözümlenmesine ve değerlendirilmesine olanak tanır. Dizeler tek, çift, üçlü tek tırnak veya üçlü çift tırnak kullanılarak tanımlanabilir. Yalnızca çift (“) (çift ve üçlü çift) alıntı dizeler enterpolasyonu destekler. Üçlü tırnaklı (üçlü tekli ve üçlü çiftli) dizeler çok satırlıdır ve dizenin içeriğini, çizgi veya yeni satır kaçış karakterleri olmadan birkaç parçaya bölmeye gerek kalmadan, çizgi sınırlarına dağıtabilirsiniz. Çift tırnak (“) (çift tırnak ve üçlü çift tırnak) ile tanımlanan dizeler enterpolasyonu destekler. Bu, herhangi bir Groovy ifadesini belirtilen konumdaki bir string ile değiştirmenize olanak tanır. Bunlara GStrings denir. Bu, ${} sözdizimi kullanılarak gerçekleştirilir. GStrings, sabit ve dinamik parçaları (değerleri) aşağıdaki örnekte gösterildiği gibi ayrı ayrı yakalamak için farklı şekilde uygulanır.
  • 118. // Groovy’de Metot Tanımlamak def say(mecburi, secimli = 'world') { def yerel_degisken = 12 def_siz_de_olur = "21" return "$mecburi $secimli! $yerel_degisken" } // say(), say(msg), say(msg, name) assert 'Hello world!' == say() assert 'Hi world!' == say('Hi') assert 'Howdy, mrhaki!' == say('Howdy,', 'mrhaki') // Boolean Evaluation println "****** Boolean Evaluation ******" def degisken = "0" // == "" için false, diğer değerler için true println "degisken: ${degisken as Boolean}" if(!(degisken as Boolean)) println "> false: degisken: "${degisken}"" else println "> true: degisken: "${degisken}"" // Integer Evaluation println "n****** Integer Evaluation ******" degisken = "31" def sayi = degisken?.isInteger() ? ++(degisken as Integer) : null println "> degisken: "${degisken}" > ${sayi}" String metinle99 = "99" sayiyla99 = Integer.parseInt(metinle99) println "> Metinle: "${metinle99}" > ${sayiyla99}" // Float Evaluation println "n****** Float Evaluation ******" degisken = "3.1" sayi = degisken?.isFloat() ? ++(degisken as Float) : null println "> degisken: "${degisken}" > ${sayi}" // Single vs Double Quotes println "n****** Single vs Double Quotes ******" println 'hi'.class.name // java.lang.String println "hi".class.name // java.lang.String def a = 'Freewind' println "hi $a" // "hi Freewind" println 'hi $a' // "hi Freewind" println "hi $a".class.name // org.codehaus.groovy.runtime.GStringImpl // Static import import static java.lang.Integer.parseInt as int_e_cevir println int_e_cevir("12") Değişkene Metot Atamak Fonksiyona Parametre Olarak Fonskiyon Geçmek Callback Fonksiyonu Parametre olarak Geçirmek def CALLBACK(){ println "İlk fonksiyon CALIS işletidi..." // değişken olarak fonksiyon/metot tanımlamak def HEDE = { println "heedeeee" } HEDE() } def CALIS( Closure cb){ println "İlk fonksiyon CALIS işletidi..." cb() } CALIS(this.&CALLBACK)
  • 119.
  • 120. String Manipulasyonları + Operator 'My name is ' + first + ' ' + last GString "My name is $name" Interpolasyon "My name is ${name}" concat() Fonksiyonu 'My name is '.concat(first).concat(' ').concat(last) leftShift() veya << Operator 'My name is ' << first << ' ' << last StringBuilder() Tipi new StringBuilder().append('My name is ').append(first).append(' ').append(last) StringBuffer() Tipi new StringBuffer().append('My name is ').append(first).append(' ').append(last) Çok Satırlı String name.first = ''' Joe Smith '''; name.last = 'Junior' .split() String[] arr = metin.split() arr.each { b -> println(b) }
  • 121. 2 Dizinin Birleştirilmesi def first = ["a", "b", "c"] def second = ["d", "e", "f"] first.addAll(second) def third = first + second // ["a", "b", "c", "d", "e", "f"] Array Fonksiyonları Array: join() Metodu ['My name is', first, last].join(' ') Array: inject() Metodu [first,' ', last] .inject(new StringBuffer('My name is '), { initial, name -> initial.append(name); return initial }).toString() Array Metotları def metin = '''./projects/cinar/cn-nef ./projects/cinar/cn-nrf ./projects/cinar/cn-nssf''' // Lambda fonksiyon (Closure) >>> ->{} def eachFonksiyonu = { a -> String ilkBes = a.substring(0,4) println(ilkBes) } metin.split().each eachFonksiyonu metin.split().each { b -> println(b) } Array - .max() Integer[] intArray = [200, 300, 100] println intArray.max() String[] stringArray = ["A", "B", "C"] println stringArray.max() Array - .min() Integer[] intArray = [200, 300, 100] println intArray.min() String[] stringArray = ["A", "B", "C"] println stringArray.min() Array - .sort() Integer[] intArray = [200, 300, 100] println intArray intArray.sort() println intArray Array - .reverse() String[] stringArray = ["A", "B", "C"] String[] reverseArray = stringArray.reverse() println stringArray println reverseArray Array - .size() == .length Integer[] arr= [200, 300, 100] println(arr.length + " == " + arr.size()) Array - [index] == .getAtt(index) Integer[] arr= [200, 300, 100] println(arr[0] + " == " + arr.getAt(0)) Array to List def list = [ 'green bay', 'packers', 'cincinnati', 'bengals'] as Object[] def map = list.toSpreadMap() null Elemanları Sil def col = [ 89, 32, null, 55 ] def r = col - null r = col.minus(null) // [89, 32, 55]
  • 122. List Liste, veri öğelerinin bir koleksiyonunu saklamak için kullanılan bir yapıdır. Groovy'de Liste, bir dizi nesne başvurusu içerir. Listedeki nesne başvuruları, dizideki bir konumu işgal eder ve bir tamsayı dizini ile ayırt edilir. Dizin esasına göre öğe ekleme ve silme yöntemlerini içeren Koleksiyonun bir alt arabirimidir. Groovy listeleri düz JDK java.util.List dir, çünkü Groovy kendi koleksiyon sınıflarını tanımlamaz. Çok boyutlu listeler de oluşturabilirsiniz. Değerleri virgülle sınırlayan ve köşeli parantez içine alan bir liste başlatabilirsiniz. Heterojen türlerin değerlerini içeren listeler de oluşturabilirsiniz. - Listenin ilk öğesine sıfır tabanlı sayım üzerinden erişebilirsiniz: hetero [0] - Listenin son öğesine negatif bir dizinle erişebilirsiniz: hetero [- 1] - Listeye bir öğe ekleyin: numbers [3] = 5 - Listenin boyutu: numbers.size () == 4
  • 123. SET
  • 124. Map
  • 125. Range
  • 126. Loop for Loop for (i = 0; i <3; i++) { System.out.println("Hello World") } for Loop With Collection List<String> list = new ArrayList<String>(); list.add("A"); list.add("B"); list.add("C"); for (String item : list) { System.out.println(item) } For Loop with Upto def c = { println it } 1.upto(4, c) Çıktı 1 2 3 4 1.upto(4, { println "Number ${it}" }) For Loop with Step 0.step 5, 1, { println it } Çıktı 0 2 4 0.step 5, 2, { println it } For Loop with Times 3.times { println "Hi ${it}" } Çıktı Hi 0 Hi 1 Hi 2 def n = 3 n.times { println "Hello ${it}" } For in for(item in ["A", "B"]) { println item } Çıktı 1 2 3 for (number in 1..3 ) { println number } For map def map = [a1:'b1', a2:'b2'] for ( item in map ) { println item.key println item.value println } Çıktı a1 b1 a2 b2 collectEntries Loop def index = 0 def result = ["bir":1,"iki":2].collectEntries { key, val-> return ["${key}_${++index}": val] // veya aşağıdaki gibi return olmaksızın dönüş sağlanabilinir. // ["${key}_${++index}": val] } println result // [bir_1:1, iki_2:2]
  • 127. Düzenli İfadeler RegExp ~// ile Düzenli İfade Tanımlamak def ipAddress = ~/([0-9]+.[0-9]+.[0-9]+.[0-9]+)/ println ipAddress.class.name // java.util.regex.Pattern ipAddress değişkeni otomatik olarak regex.Pattern olmuş! Eşleşti mi? def nameRegex = ~’john’ println nameRegex.matcher("john").matches() // true def ipAddressRegex = ~/([0-9]+.[0-9]+.[0-9]+.[0-9]+)/ println ipAddressRegex.matcher("127.0.0.1").matches() // true
  • 129. SH sh Komutu script (opt.boolean): returnStdout (opt.boolean): Returns the standard output stream with a default encoding of UTF-8 (alternative encoding is optional) returnStatus (opt. boolean): Returns the exit status (integer) of the PowerShell script 0 Olmayan exit kodları hatalı olarak script sonlandı demektir. Buna göre tüm jenkins build’i hakkında işaretleme yapabilir, sonraki işlere devam edebilir ya da kesebiliriz. def statusCode = sh script:script, returnStatus:true currentBuild.result = 'FAILURE' currentBuild.result = 'UNSTABLE' label (opt. string): Label to be displayed in the pipeline step view and blue ocean details for the step instead of the step type. So the view is more meaningful and domain specific instead of technical. encoding (opt. string): Eğer returnStdout: true olarak işaretlenmişse sh’ın çıktısını okuyacağız demektir ve okunacak metnin kodlaması default olarak UTF-8 olmasına rağmen değiştirilebilir (encoding: 'UTF-8') For Loop with Upto def c = { println it } 1.upto(4, c) Çıktı 1 2 3 4 1.upto(4, { println "Number ${it}" }) For map def map = [a1:'b1', a2:'b2'] for ( item in map ) { println item.key println item.value println } Çıktı a1 b1 a2 b2 try { npmViewOutput = sh(returnStdout: true, script: "npm view olmayan_paket") } catch (Exception e) { echo "${e.message}" }
  • 131. Değişken Tanımlama Jenkinsfile dosyasındaki değişkenler def anahtar sözcüğü kullanılarak tanımlanabilir. Bu değişkenler pipeline bloğu başlamadan önce tanımlanmalıdır. Değişken tanımlandığında, ${...} sözdizimi kullanılarak Jenkins declarative script düzeninden çağrılabilir. Globalde tanımlı değiken adı yerelde tekrar tanımlanamaz! The current scope already contains a variable of the name myVar def myVariable = "foo" pipeline { agent any stages { stage ("Print variable") { steps { echo "My variable is ${myVar}" } } } } Koşullu Değişkenler Groovy dili, Jenkins pipeline’da kullanılabilen koşullu yapıları destekler. Parametreli bir job ve bir Jenkinsfile dosyasında, sağlanan parametrelere bağlı olarak tanımlanması gereken bir değişkeniniz olduğunu varsayın. // Define variables // and convert them to lowercase def role = params.ROLE.toLowerCase() def env = params.ENVIRONMENT.toLowerCase() // Conditionally define a variable 'impact' if (role == 'front' && env == 'prod') { impact = "high" } else if (role == 'front' && env == 'dev') { impact = "low" } else if (role == 'db' && env == 'stg') { impact = "medium" } else { impact = "unknown" } // 'impact' değişkenini Jenkins pipeline’a yaz pipeline { agent any stages { stage ("Impact") { steps { echo "The impact is ${impact}" } } } } Koşullu Çalışacak Aşamalar Eğer dosya varsa (fileExists) aşama çalıştırılacak, yoksa başka bir aşama çalıştırılacak. Environment 3 şekilde tanımlanıyordu, global olanı Jenkins Global Properties içinde Environment Variables alanında. Inject edilebilen env. var. EnvInject plugin sayesinde. Ve local env. değişken olarak pipeline içinde tanımlanır. pipeline{ agent any environment{ MY_FILE = fileExists '/tmp/myfile' } stages{ stage('dosya varsa aşaması'){ when { expression { MY_FILE == 'true' } } steps { echo "file exists" } } stage('Dosya yoksa aşaması'){ when { expression { MY_FILE == 'false' } } steps { echo "file does not exist" } } } } def myVar = "globalde tanımlı" ... stage ("yerel") { steps { def myVar = "2. kez olmaz" } }
  • 132. findFiles ile Dosya Bulmak def files = findFiles glob: '**/reports/*.json' for (def i=0; i<files.length; i++) { jsonFilePath = "${files[i].path}" jsonPath = "${env.WORKSPACE}" + "/" + jsonFilePath echo jsonPath readJSON ile JSON dosyasını/metnini değişkene atama yap stages { stage('readJSON angular.json') { steps{ script { def json = readJSON file: './angular.json' def projects = json['projects'] projects = json.projects if(json.projects){ // sadece e2e testleri olan projeleri MAP içinde saklayalım def e2eProjeleri = [:] json.projects.each { key, value -> println "KEY:" + key + " <> VALUE:" + value.projectType println " >> value.architect.e2e: "+value.architect.e2e // value.architect.e2e değeri null olduğunda falsey değer olacaktır. // Aksi halde truthy olacak ve if şartına girecek if(value.architect.e2e){ e2eProjeleri[key] = [a: value.architect.e2e, b: "cem"] } } e2eProjeleri.each{ k, v -> println k } } } } } }
  • 133. readJSON ve returnPojo ile LinkedHashMap veya JSONObject türüne dönüştürmek
  • 135. Environment Variable İşletim sisteminin ortam değişkenlerine windows için %DeğişkenAdı% , linux için $DeğişkenAdı ile erişiyoruz. Ortam değişkenleri tüm hat içerisinden erişilebilen yerel ve global değişkenlerdir. İşletim sistemi seviyesinde tanımlı env. vars’a erişmek için windows os üstünde koşan bir batch için $env.PATH,
  • 136. Nasıl ve hangi sırayla eziliyor env vars? def PATH = "En üstte tanımlı global degisken" pipeline { agent any stages { stage("a"){ environment{ PATH = "local env. var. PATH" } steps{ /** * $env.XXX ile değişkenler; * varsa * önce local env, * sonra Jenkins env * sonra OS env * seviyesinde PATH değişkenin arar * * localde env.PATH bulur ve onu yazar **/ echo "$env.PATH" } } stage("b"){ // önce değikenlerde arar ve globalde PATH değişkeni bulur steps{ echo "$PATH" } } stage("c"){ environment { PATH = "yerel env içinde tanımlı" } // env.PATH olmadığı için önce değikenlerde arar. Local'de PATH adında değişken yok! // globalde (en üstte) tanımlı PATH değişkenini bulur steps{ echo "$PATH" } } stage("ç"){ // Local env de PATH yok. Jenkins seviyesinde env.PATH bulur onu yazar steps{ echo "$env.PATH" } } stage("d"){ environment{ PATH = "Ezdi mi ne?" } // local env.PATH bulur ve onu yazar steps{ echo "$env.PATH" } } } Env Var Sıralaması $env.XXX ile erişilmek istenen ortam değişkenleri aşağıdaki sıralama ile aranır. İlk bulunduğu yerde değeri kullanılır. Bulunamazsa değer olara null kullanılır. stage("a"){ environment{ PATH = "local env. var. PATH" } steps{ /** * $env.XXX ile değişkenler; * varsa * önce local env, * sonra Jenkins env * sonra OS env * seviyesinde PATH değişkenin arar **/ echo "$env.PATH" }
  • 137. Global ve Local Değişkenler ve Local Ortam Değişkenleri def global_degisken = "En üstte tanımlı global degisken" pipeline { agent any stages { stage("a"){ environment{ aDegiskeni = "A" } steps{ echo "------- STAGE A >>>>>>>>>>>" echo "global_van: $global_degisken" echo "local env aDegiskeni: “ echo "$aDegiskeni = $env.aDegiskeni = ${env.aDegiskeni} = ${aDegiskeni}" /** bDegiskeni tanımlı olmadığı için hata verir * groovy.lang.MissingPropertyException: * No such property: bDegiskeni for class: groovy.lang.Binding * echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni" */ echo "<<<<<<<<<< STAGE A --------------" } } stage("b"){ environment{ bDegiskeni = "B" } steps{ echo "------- STAGE B >>>>>>>>>>>" echo "global_van: $global_degisken" /** aDegiskeni yerelde veya globalde tanımlı bir değişken olsa erişilebilir. * Oysa A aşamasında env'e bağlı yaratlıyor ancak burada env olmadan * yani $aDegiskeni veya = ${aDegiskeni} diyerek erişilmek isteniyor * Bu yüzden istisna fırlatacak ve build son bulacak. * groovy.lang.MissingPropertyException: * No such property: aDegiskeni for class: groovy.lang.Binding */ echo "local env aDegiskeni: $env.aDegiskeni = ${env.aDegiskeni}" echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni" echo "<<<<<<<<<< STAGE B --------------" } } } }
  • 138. env-vars.html ${YOUR_JENKINS_HOST}/env-vars.html shell Komutuyla pipeline { agent any stages { stage("Env Variables") { steps { sh "printenv" } } } } ortam değişkenlerine değer atamak pipeline { agent any environment { FOO = "bar" } stages { stage("Env Variables") { environment { NAME = "Alan" } steps { echo "FOO = ${env.FOO}" script { env.TEST_VARIABLE = "some test value" } echo "TEST_VARIABLE = ${env.TEST_VARIABLE}" withEnv(["BASKA_ENV_VAR=başka değer"]) { echo "BASKA_ENV_VAR = ${env.BASKA_ENV_VAR}" } } } } } ortam değişkenlerinde BOOLEAN script { if (env.IS_BOOLEAN) { echo ""false" String Boolean.TRUE değerine dönüşür" } if (env.IS_BOOLEAN.toBoolean() == false) { echo ""false".toBoolean() ise Boolean.FALSE olur" } } ortam değişkenlerine shell’den değer atamak pipeline { agent any environment { LS = "${sh(script:'ls -lah', returnStdout: true)}" } stages { stage("Env Variables") { steps { echo "LS = ${env.LS}" } } } } ortam değişkenlerini okumak Yerelde tanımlı olmayan değişkeni global de ve en üstte ortam değişkenlerinde arar. pipeline { agent any stages { stage("Env Variables") { steps { echo "1. Yöntem: ${env.BUILD_NUMBER}" echo "2. Yöntem: ${BUILD_NUMBER} -> ${BUILD_NUMBER}" sh 'echo "3. Yöntem: $BUILD_NUMBER"' } } } }
  • 139. pipeline { agent any environment { FOO = "bar" NAME = "Joe" } stages { stage("Env Variables") { environment { NAME = "Alan" // overrides pipeline level NAME env variable BUILD_NUMBER = "2" // overrides the default BUILD_NUMBER } steps { echo "FOO = ${env.FOO}" // prints "FOO = bar" echo "NAME = ${env.NAME}" // prints "NAME = Alan" echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 2" script { env.SOMETHING = "1" // creates env.SOMETHING variable } } } stage("Override Variables") { steps { script { env.FOO = "IT DOES NOT WORK!" // it can't override env.FOO declared at the pipeline (or stage) level env.SOMETHING = "2" // it can override env variable created imperatively } echo "FOO = ${env.FOO}" // prints "FOO = bar" echo "SOMETHING = ${env.SOMETHING}" // prints "SOMETHING = 2" withEnv(["FOO=foobar"]) { // it can override any env variable echo "FOO = ${env.FOO}" // prints "FOO = foobar" } withEnv(["BUILD_NUMBER=1"]) { echo "BUILD_NUMBER = ${env.BUILD_NUMBER}" // prints "BUILD_NUMBER = 1" } } } } }
  • 140. Globalde Tanımlı Özel Env. Var. Jobların erişmesini istediğiniz temel değerleri global env. vars. içinde tanımlayabilirsiniz. Örneğin sprint koşunuzun numarası, üretilecek projenin versiyon numarası vs. için değerleri globalde bir kere tanımlayıp tüm projeler için globaldeki değişkenler gibi (örneğin BUILD_NUMBER’a WORKSPACE’e erişir gibi) erişebilirsiniz.
  • 142. Declrative Jenkins Yeni bir proje başlatıyor ve pipeline türünde seçerek adını yazıyoruz. Daha sade bir yapıda gelecek. Pipeline içinde scriptimizi yazıyoruz. Yardıma ihtiyacımız olduğu yerlerde “Pipeline Syntax” bağlantısından bizim için script üretmesini isteyebiliriz.
  • 143. pipeline { } İlk ifademiz pipeline olacak ve tüm yönergelerimiz pipeline bloğunun içinde olmalıdır Declarative Pipeline’ı Anlamak pipeline { agent any } Herhangi uygun agent üstünde çalışacak diye işaretledik. Etikete göre agent seçmek: agent { label '!windows' } pipeline { agent any tools { git ‘localGit’ jdk ‘localJava’ nodejs ‘localNode’ } } Jenkins'te kullanılacak araçları tools ile belirtiriz. Araçlar (tools), Jenkins düğümünde yüklü olan yapılandırma (build) araçlarından başka bir şey değildir. Global Tool Configuration altında belirttiğimiz çalıştırılabilir uygulamaların yollarını takma adlarla tanımlamıştık. tools Altındaki araçlar için bu takma adları kullanıyoruz. pipeline { agent any environment { global_degisken = 'true' } stages { stage ('derle') { environment { yerel_degisken = '12' } steps { echo 'Değer: '+yerel_degisken } } } } Ortam değişkenleri global veya stage özelinde ayarlanabilir. Stage başına ayarlanmış değişkenler sadece tanımlı olunan stage için geçerli olacaktır. Global Tool Configuration altında belirttiğimiz çalıştırılabilir uygulamaların yollarını takma adlarla tanımlamıştık. tools Altındaki araçlar için bu takma adları kullanıyoruz. DSL ile Jenkins Script arasındaki fark; daha kolay kodlama yapabileceğimiz Domain Specific Language olarak tanımlayabiliriz.
  • 144. Declarative Jenkins Pipeline (1) Pipeline türünde bir proje başlatalım. İçinde Jenkinsfile (4) adında dosya ve aşamaları barındıran bir script dosyası da olacak github projesi (2) oluşturalım. Jenkins job’ının içinde Pipeline kısmında bir Source Control Management (3) üstünden Jenkinsfile dosyasını çekeceğimizi belirtelim. Çalıştırdığımızda git çekilir ve Jenkinsfile çalıştırılır(5). 1 2 3 4 5
  • 145. bat 'powershell -noexit "& "".run-tests.ps1"""' steps { echo "build içindeki steps" bat "echo %path%" bat "sh --help" bat "npm --version && npm start" } 'cmd' is not recognized as an internal or external command, operable program or batch file. İster stage içinde ister tüm pipeline içindeki environment ayarına cmd.exe dosyasını erişilebilir hale getirmeli: environment { PATH = "C:WINDOWSSYSTEM32;" } 'npm' is not recognized as an internal or external command, operable program or batch file. npm adında çalıştırılabilir dosyayı erişilebilir hale getirmek için NodeJS aracını tools altına eklemeli: tools { nodejs "node_js" // Global Conf. Tools altında tanımlı araç adı } Ok-Cancel Sorusu sormak için input message kullanılır input message: "Devam etmek için Proceed bağlantısına tıkla, iptal için Abort'a tıkla" pipeline { agent none stages { stage('Integration Test') { agent { label 'windows_agent' } steps { script { docker.image('mongo:3.4').withRun(' -p 27017:27017') { c -> sh "echo ayaklandı" } } } } } }
  • 147. error Kendimiz hata uydurmak istersek error(mesajımız) fonksiyonunu kullanırız. try { error("Hata mesajı") } catch (e) { echo 'Hata: ' + e.toString() throw e } finally { // çalışır }
  • 148. try-catch-finally stage('checkout') { try { … if (your condition) { autoCancelled = true error('Kritik hata oluştu') } } catch (e) { if (e.message == "Devam edilecek istisna") { currentBuild.result = 'ABORTED' echo('return yaparsak sonraki stage çalışır') return } echo('throw yaparsak sonraki stage çalışmaz') throw e } finally { echo('her şeye rağmen çalıacak satır') } }
  • 149. retry(n) retry(2) { try { prepareEnvironment() setupBuildEnvironment() // sets up environment if it is not present yet runBuild() } catch (e) { echo 'Err: Build failed with Error: ' + e.toString() echo ' Trying to build with a clean Workspace' removeOldBuildEnvironment() throw e } finally { cleanupEnvironment() } }
  • 150. catchError Birden fazla projenin kullandığı ortak kütüphanede mi değişiklik yaparak hepsini etkilemek istersiniz yoksa tek tek her projeye gidip değişiklik mi yapmak istersiniz?
  • 152. Neden Shared library? Birden fazla projenin kullandığı ortak kütüphanede mi değişiklik yaparak hepsini etkilemek istersiniz yoksa tek tek her projeye gidip değişiklik mi yapmak istersiniz? Paylaşılan kitaplık deposu klasör yapısına sahiptir. (root) +- src # Groovy source files | +- org | +- foo | +- Bar.groovy # for org.foo.Bar class +- vars | +- foo.groovy # for global 'foo' variable +- resources # resource files | +- org | +- foo | +- bar.json # static helper data for org.foo.Bar

Editor's Notes

  1. https://www.edureka.co/blog/jenkins-pipeline-tutorial-continuous-delivery https://www.slideshare.net/StephenKing/declarative-jenkins-pipelines
  2. https://java2blog.com/jenkins-tutorial/
  3. https://jenkins.io/blog/2017/02/01/pipeline-scalability-best-practice/
  4. https://e.printstacktrace.blog/jenkins-scripted-pipeline-vs-declarative-pipeline-the-4-practical-differences/
  5. https://www.slideshare.net/StephenKing/declarative-jenkins-pipelines https://www.blazemeter.com/blog/how-to-use-the-jenkins-declarative-pipeline/
  6. https://jenkins.io/blog/2018/04/09/whats-in-declarative/ https://jenkins.io/blog/2017/01/19/converting-conditional-to-pipeline/ https://www.cyotek.com/blog/using-parameters-with-jenkins-pipeline-builds
  7. https://www.blazemeter.com/blog/how-to-use-the-jenkins-declarative-pipeline/
  8. https://www.edureka.co/community/54705/difference-between-declarative-pipeline-scripted-pipeliine
  9. https://www.youtube.com/watch?v=m47MWSXNslg
  10. https://wiki.jenkins.io/display/JENKINS/Installing+Jenkins+with+Docker
  11. docker run --name CEMkins ^ -p 8080:8080 ^ -p 50000:50000 ^ -v //C:/Users/cem.topkaya/Documents/Kitematic/jenkins/var/jenkins_home ^ jenkins/jenkins
  12. https://askubuntu.com/questions/706186/difference-between-and-in-linux-environment
  13. https://medium.com/@gustavo.guss/jenkins-starting-with-pipeline-doing-a-node-js-test-72c6057b67d4
  14. Terminal giriş komutu: docker exec --user root -it jenkins bash Kurulum komutu: apt-get update \ && apt-get upgrade -y \ && curl -sL https://deb.nodesource.com/setup_12.x | bash - \ && apt-get install -y nodejs \ && npm --version
  15. https://rollout.io/blog/the-basics-of-the-docker-run-command/
  16. https://www.katacoda.com/courses/docker/2
  17. https://support.cloudbees.com/hc/en-us/articles/360027646491-Pipeline-Equivalent-to-Git-Publisher?page=14
  18. https://medium.com/@pierangelo1982/setting-ssh-connection-to-ubuntu-on-virtualbox-af243f737b8b https://www.malwaredatascience.com/ubuntu-virtual-machine
  19. https://www.computerhope.com/unix/uifconfi.htm https://www.computerhope.com/unix/ifup.htm -a Display information for all network interfaces, even if they are down. -s Display a short list in a format identical to the command "netstat -i". -v Verbose mode; display additional information for certain error conditions. interface The name of the interface. This is usually a driver name followed by a unit number, for example "eth0" for the first Ethernet interface. If your kernel supports alias interfaces, you can specify them with eth0:0 for the first alias of eth0. You can use them to assign a second address. To delete an alias interface, use ifconfig eth0:0 down. Note: for every scope (i.e. same net with address/netmask combination) all aliases are deleted, if you delete the first (primary). up This flag causes the interface to be activated. It is implicitly specified if an address is assigned to the interface. down This flag causes the driver for this interface to be shut down. [-]arp Enable (or disable, if the "-" prefix is specified) the use of the ARP protocol on this interface. [-]promisc Enable (or disable, if the "-" prefix is specified) the promiscuous mode of the interface. If promiscuous mode is enabled, all packets on the network will be received by the interface. [-]allmulti Enable or disable all-multicast mode. If multicast mode is enabled, all multicast packets on the network will be received by the interface. metric N This parameter sets the interface metric, which is used by the interface to make routing decisions. N must be an integer between 0 and 4294967295. If you're not sure what a network metric is, or whether you should change it, you can safely leave this setting alone. mtu N This parameter sets the MTU (maximum transfer unit) of an interface. This setting is used to limit the maximum packet size transferred by the interface. If you're not sure about it, you can safely leave this setting alone. dstaddr address Set the remote IP address for a point-to-point link (such as PPP). This keyword is now obsolete; use the pointopoint keyword instead. netmask address Set the IP network mask for this interface. This value defaults to the usual class A, B or C network mask (as derived from the interface IP address), but it can be set to any value. add address/prefixlen Add an IPv6 address to an interface. del address/prefixlen Remove an IPv6 address from an interface. tunnel aa.bb.cc.dd Create a new SIT (IPv6-in-IPv4) device, tunnelling to the given destination. irq address Set the interrupt line used by this device. Not all devices can dynamically change their IRQ setting. io_addr address Set the start address in I/O space for this device. mem_start address Set the start address for shared memory used by this device. Only a few devices need this. media type Set the physical port or medium type to be used by the device. Not all devices can change this setting, and those that can vary in what values they support. Typical values for type are 10base2 (thin Ethernet), 10baseT (twisted-pair 10Mbps Ethernet), AUI (external transceiver), etc. The special medium type of auto can be used to tell the driver to auto-sense the media. Again, not all drivers can do this. [-]broadcast [address] If the address argument is given, this will set the protocol broadcast address for this interface. Otherwise, it will set (or clear, if the "-" prefix is used) the IFF_BROADCAST flag for the interface. [-]pointopoint [address] This keyword enables the point-to-point mode of an interface, meaning that it is a direct link between two machines with nobody else listening on it. If the address argument is also given, set the protocol address of the other side of the link, just like the obsolete dstaddr keyword does. Otherwise, set or clear the IFF_POINTOPOINT flag for the interface. hw class address Set the hardware address of this interface, if the device driver supports this operation. The keyword must be followed by the name of the hardware class and the printable ASCII equivalent of the hardware address. Hardware classes currently supported include ether (Ethernet), ax25 (AMPR AX.25), ARCnet and netrom (AMPR NET/ROM). multicast Set the multicast flag on the interface. This should not normally be needed as the drivers set the flag correctly themselves. address The IP address to be assigned to this interface. txqueuelen length Set the length of the transmit queue of the device. It is useful to set this to small values for slower devices with a high latency (such as a connection over a modem, or over ISDN) to prevent fast bulk transfers from disturbing interactive traffic like telnet too much. Examples ifconfig Running ifconfig with no options displays the configuration of all active interfaces. ifconfig -a Displays the configuration of all interfaces, both active and inactive. ifconfig eth0 View the network settings on the interface eth0, which (under Linux) is the first Ethernet adapter installed in the system. ifconfig eth1 up Activate the network interface eth1. ifconfig wlan0 down Deactivate the network interface wlan0. ifconfig wlan1 122.140.201.66 Configure the network interface wlan1 to use the static IP address 122.140.201.66. ifconfig wlan0 netmask 255.255.255.0 Configure the network interface wlan0 to use the network mask 255.255.255.0. ifconfig eth0 192.168.1.102 netmask 255.255.255.0 broadcast 192.168.1.255 Configure eth0 to use the static IP address 192.168.1.102 using the network mask 255.255.255.0, and the broadcast address 192.168.1.255.
  20. https://thishosting.rocks/install-java-ubuntu/ UNINSTALL ORACLE JDK Remove The Link First of all remove the alternatives by executing the following commands: $ sudo update-alternatives --remove "java" "/usr/lib/jvm/jdk[version]/bin/java" $ sudo update-alternatives --remove "javac" "/usr/lib/jvm/jdk[version]/bin/javac" $ sudo update-alternatives --remove "javaws" "/usr/lib/jvm/jdk[version]/jre/bin/javaws" Note: Replace the [version] with any version number that’s contained in jdk folder’s name. For example: jdk1.8.0_131. Remove The Package After removing link, remove the package inside /usr/lib/jvm/jdk[version] by executing following command: $ sudo rm -r /usr/lib/jvm/jdk[version] UNINSTALL OPENJDK If you want to remove Openjdk only, execute the following command on terminal: $ sudo apt-get remove openjdk* If you want to remove Openjdk along with dependencies, execute the following command on terminal: $ sudo apt-get remove --auto-remove openjdk* If you want to remove Openjdk and it’s configuration files, execute the following command on terminal: $ sudo apt-get purge openjdk* If you want to remove Openjdk along with dependencies and it’s configuration files, execute the following command on terminal: $ sudo apt-get purge --auto-remove openjdk* This is how you can uninstall JDK.
  21. https://www.cyberciti.biz/faq/linux-list-processes-by-user-names-euid-and-ruid/ https://stackoverflow.com/questions/28103045/how-can-i-delete-a-user-in-linux-when-the-system-says-its-currently-used-in-a-pr https://devconnected.com/how-to-add-and-delete-users-on-debian-10-buster/
  22. https://www.hostinger.web.tr/rehberler/ssh-nedir https://www.linuxliteos.com/forums/tutorials/tutorial-configure-linux-lite-3-0-ad-hoc-wifi-ssh-from-other-linux-computer/
  23. https://stackoverflow.com/questions/19018385/host-key-verification-failed https://stackabuse.com/how-to-fix-warning-remote-host-identification-has-changed-on-mac-and-linux/ https://askubuntu.com/questions/265982/unable-to-start-sshd
  24. https://github.com/jenkinsci/docker/issues/594
  25. https://stackoverflow.com/questions/19018385/host-key-verification-failed https://stackabuse.com/how-to-fix-warning-remote-host-identification-has-changed-on-mac-and-linux/ https://askubuntu.com/questions/265982/unable-to-start-sshd
  26. https://support.cloudbees.com/hc/en-us/articles/115000073552-Host-Key-Verification-for-SSH-Agents Detaylı ve güzel anlatımı yukarıdaki adreste. Know Hosts file Verification Strategy: use the Known Host file, configuration outside Jenkins Manually provided Verification Strategy: provide the host key directly from Jenkins Manually trusted Verification Strategy: trust the host key from Jenkins Non verifying Verification Strategy: legacy behavior, no host key verification
  27. https://rominirani.com/docker-tutorial-series-part-6-docker-private-registry-15d1fd899255
  28. UNINSTALL ORACLE JDK Remove The Link First of all remove the alternatives by executing the following commands: $ sudo update-alternatives --remove "java" "/usr/lib/jvm/jdk[version]/bin/java" $ sudo update-alternatives --remove "javac" "/usr/lib/jvm/jdk[version]/bin/javac" $ sudo update-alternatives --remove "javaws" "/usr/lib/jvm/jdk[version]/jre/bin/javaws" Note: Replace the [version] with any version number that’s contained in jdk folder’s name. For example: jdk1.8.0_131. Remove The Package After removing link, remove the package inside /usr/lib/jvm/jdk[version] by executing following command: $ sudo rm -r /usr/lib/jvm/jdk[version] UNINSTALL OPENJDK If you want to remove Openjdk only, execute the following command on terminal: $ sudo apt-get remove openjdk* If you want to remove Openjdk along with dependencies, execute the following command on terminal: $ sudo apt-get remove --auto-remove openjdk* If you want to remove Openjdk and it’s configuration files, execute the following command on terminal: $ sudo apt-get purge openjdk* If you want to remove Openjdk along with dependencies and it’s configuration files, execute the following command on terminal: $ sudo apt-get purge --auto-remove openjdk* This is how you can uninstall JDK.
  29. https://jenkins.io/doc/pipeline/steps/workflow-scm-step/ https://code-maven.com/jenkins-git-check-out-using-reference https://jenkins.io/doc/pipeline/steps/credentials-binding/
  30. https://aykutfarsak.com/jenkins-kurulumu-ubuntu
  31. https://cheatsheet.dennyzhang.com/cheatsheet-jenkins-groovy-a4
  32. https://livebook.manning.com/book/groovy-in-action-second-edition/chapter-3/28
  33. groovy-net Build a URI or URL Convert query string from map Get webpage content form URL Make a get request to a URI or URL
  34. https://www.leveluplunch.com/groovy/examples/#groovy-string groovy-string Count number of chars in string Left pad string with spaces Remove first char from string Remove last char from string Remove part of a string Right pad string with spaces Split string on comma Split string on white space
  35. https://stackoverflow.com/a/1716699/104085 ternary ve null check https://groovy-lang.org/closures.html
  36. https://stackoverflow.com/a/1716699/104085 ternary ve null check https://groovy-lang.org/closures.html
  37. https://dzone.com/articles/concatenate-strings-in-groovy
  38. https://dzone.com/articles/concatenate-strings-in-groovy https://innovalog.atlassian.net/wiki/spaces/JMWE/pages/152568042/Data+types+in+Groovy#DatatypesinGroovy-Arrays https://www.leveluplunch.com/groovy/examples/ groovy-collections Calculate average of list Combine two lists Convert list to map Count non empty strings in arraylist Count occurrences of element in list Count occurrences of key or value in map Count true values in list Filter list by class field Find max value in arraylist Find min value in arraylist Get First/Last element in ArrayList Get a subset of a map Get longest string in list Get smallest string in list Limit number of elements in arraylist Partition / Split / Collate arraylist Remove null from list Sort map dictionary by key Sort map dictionary by value Sum elements of arraylist
  39. https://innovalog.atlassian.net/wiki/spaces/JMWE/pages/152568042/Data+types+in+Groovy#DatatypesinGroovy-Arrays https://www.tutorialspoint.com/groovy/groovy_lists.htm
  40. https://innovalog.atlassian.net/wiki/spaces/JMWE/pages/152568042/Data+types+in+Groovy#DatatypesinGroovy-Arrays
  41. https://innovalog.atlassian.net/wiki/spaces/JMWE/pages/152568042/Data+types+in+Groovy#DatatypesinGroovy-Arrays https://www.tutorialspoint.com/groovy/groovy_maps.htm
  42. https://innovalog.atlassian.net/wiki/spaces/JMWE/pages/152568042/Data+types+in+Groovy#DatatypesinGroovy-Arrays https://www.tutorialspoint.com/groovy/groovy_ranges.htm
  43. http://grails.asia/groovy-for-loop-examples
  44. http://grails.asia/groovy-for-loop-examples
  45. https://e.printstacktrace.blog/jenkins-pipeline-environment-variables-the-definitive-guide/
  46. https://stackoverflow.com/a/42434221/104085 https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#code-sh-code-shell-script
  47. https://e.printstacktrace.blog/jenkins-pipeline-environment-variables-the-definitive-guide/
  48. https://support.cloudbees.com/hc/en-us/articles/360027607532-Pipeline-with-conditional-stages-based-on-a-file-existing-on-the-filesystem https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#fileexists-verify-if-file-exists-in-workspace https://stackoverflow.com/questions/38534781/check-if-a-file-exists-in-jenkins-pipeline
  49. pipeline { agent {label "UI_demo_node"} options { parallelsAlwaysFailFast() } stages { stage('LinkedHashMap tipinde saklar') { steps{ script { def a = [:] a["bir"] = 1 a["nesne"] = [n:"es", ne:"neee"] println a // {bir=1, nesne={n=es, ne=neee}} println a.getClass() // class java.util.LinkedHashMap def jsonstring = '{ "key": null, "a": "b", "c": { "d":"dee", "e": [1,2] }, "dizi": [{ "di":"zi", "zi": 2 }] }' def pojoTrue = readJSON text: jsonstring, returnPojo: true println pojoTrue // {key=null, a=b, c={d=dee, e=[1, 2]}, dizi=[{di=zi, zi=2}]} println pojoTrue.getClass() // class java.util.LinkedHashMap def pojoFalse = readJSON text: jsonstring, returnPojo: false println pojoFalse // {"key":null,"a":"b","c":{"d":"dee","e":[1,2]},"dizi":[{"di":"zi","zi":2}]} println pojoFalse.getClass() // class net.sf.json.JSONObject } } }
  50. https://e.printstacktrace.blog/jenkins-pipeline-environment-variables-the-definitive-guide/ https://code-maven.com/jenkins-pipeline-environment-variables
  51. https://www3.ntu.edu.sg/home/ehchua/programming/howto/Environment_Variables.html https://code-maven.com/jenkins-pipeline-environment-variables
  52. def global_degisken = "En üstte tanımlı global degisken" pipeline { agent any stages { stage("a"){ environment{ aDegiskeni = "A" } steps{ echo "------- STAGE A >>>>>>>>>>>" echo "global_van: $global_degisken" echo "local env aDegiskeni: $aDegiskeni = $env.aDegiskeni = ${env.aDegiskeni} = ${aDegiskeni}" /** bDegiskeni tanımlı olmadığı için hata verir * groovy.lang.MissingPropertyException: No such property: bDegiskeni for class: groovy.lang.Binding * echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni" */ echo "<<<<<<<<<< STAGE A --------------" } } stage("b"){ environment{ bDegiskeni = "B" } steps{ echo "------- STAGE B >>>>>>>>>>>" echo "global_van: $global_degisken" /** aDegiskeni yerelde veya globalde tanımlı bir değişken olsa erişilebilir. * Oysa A aşamasında env'e bağlı yaratlıyor ancak burada env olmadan * yani $aDegiskeni veya = ${aDegiskeni} diyerek erişilmek isteniyor * Bu yüzden istisna fırlatacak ve build son bulacak. * groovy.lang.MissingPropertyException: No such property: aDegiskeni for class: groovy.lang.Binding */ echo "local env aDegiskeni: $env.aDegiskeni = ${env.aDegiskeni}" echo "local env bDegiskeni: $bDegiskeni - $env.bDegiskeni" echo "<<<<<<<<<< STAGE B --------------" } } } }
  53. pipeline { agent any stages { stage('kaynak kodu çek'){ steps { echo "kod çekildi başarılı" } } stage('derle'){ steps { echo "Derleme başarılı" } } stage('test et'){ steps { echo "Test sorunsuz başarılı" } } stage('Sürüm yap'){ steps { echo "versiyonlandı" } } stage('UAT için yükle'){ steps { echo "Kullanıcı Kabul Testi için yükleme başarılı" } } } post{ always { echo "post - Her zaman bunu yazacak" } success { echo "post - SUCCESS olduğunda bunu yazacak" } failure { echo "post - FAIL olduğunda bunu yazacak" } unstable { echo "post - UNSTABLE olduğunda bunu yazacak" } changed { echo "post - CHANGED olduğunda bunu yazacak" } } }
  54. https://medium.com/@sportans300/jenkins-pipeline-to-deploy-angular-app-to-appengine-gcp-1f58160e2779
  55. https://www.blazemeter.com/blog/how-to-use-the-jenkins-declarative-pipeline/