{"id":222,"date":"2026-09-11T12:00:00","date_gmt":"2026-09-11T12:00:00","guid":{"rendered":"https:\/\/konteynerium.com\/?p=222"},"modified":"2026-10-06T11:34:00","modified_gmt":"2026-10-06T11:34:00","slug":"jenkins-ile-cicd-docker-imajlarini-otomatik-build-deploy","status":"publish","type":"post","link":"https:\/\/konteynerium.com\/index.php\/2026\/09\/11\/jenkins-ile-cicd-docker-imajlarini-otomatik-build-deploy\/","title":{"rendered":"Jenkins ile CI\/CD: Docker \u0130majlar\u0131n\u0131 Otomatik Build ve Deploy Etme"},"content":{"rendered":"<p>&#8220;CI\/CD ile Docker&#8221; yaz\u0131m\u0131zda GitHub Actions \u00fczerinden bulut tabanl\u0131 bir pipeline kurmu\u015ftuk. Ama bir\u00e7ok kurumsal ekip h\u00e2l\u00e2 <strong>Jenkins<\/strong>&#8216;i tercih ediyor \u2014 kendi sunucunuzda bar\u0131nd\u0131rd\u0131\u011f\u0131n\u0131z, y\u00fczlerce eklentiyle her t\u00fcrl\u00fc araca entegre olabilen, a\u00e7\u0131k kaynak bir otomasyon sunucusu. Bu yaz\u0131da Jenkins&#8217;i bizzat bir Docker container&#8217;\u0131 olarak aya\u011fa kald\u0131r\u0131p, Docker imajlar\u0131n\u0131 otomatik build eden ger\u00e7ek bir pipeline kuruyoruz.<\/p>\n<h2>Jenkins neden h\u00e2l\u00e2 yayg\u0131n?<\/h2>\n<p>GitHub Actions ve GitLab CI gibi bulut tabanl\u0131 \u00e7\u00f6z\u00fcmler daha az yap\u0131land\u0131rmayla h\u0131zl\u0131 sonu\u00e7 verse de, Jenkins&#8217;in tercih edilmesinin somut nedenleri var:<\/p>\n<ul>\n<li><strong>Tam kontrol:<\/strong> Kendi sunucunuzda \u00e7al\u0131\u015f\u0131r \u2014 kod ve build s\u00fcre\u00e7leri hi\u00e7bir zaman \u00fc\u00e7\u00fcnc\u00fc parti bir buluta \u00e7\u0131kmaz. S\u0131k\u0131 veri gizlili\u011fi gereksinimleri olan kurumlar i\u00e7in \u00f6nemli.<\/li>\n<li><strong>Eklenti ekosistemi:<\/strong> 1800&#8217;den fazla resmi eklenti; neredeyse her ara\u00e7, versiyon kontrol sistemi ve bildirim kanal\u0131yla (Slack, Jira, SonarQube, Artifactory&#8230;) entegre olabilir.<\/li>\n<li><strong>Karma altyap\u0131 deste\u011fi:<\/strong> \u015eirket i\u00e7i (on-premise) sunucular, farkl\u0131 i\u015fletim sistemleri, \u00f6zel donan\u0131mlar (GPU build ajanlar\u0131 gibi) \u00fczerinde \u00e7al\u0131\u015fabilir \u2014 bulut tabanl\u0131 runner&#8217;lar\u0131n eri\u015femeyece\u011fi ortamlarda.<\/li>\n<li><strong>Olgunluk:<\/strong> 2011&#8217;den beri geli\u015ftiriliyor; b\u00fcy\u00fck kurumsal ortamlarda onlarca y\u0131ll\u0131k production ge\u00e7mi\u015fi var.<\/li>\n<\/ul>\n<h2>Mimari: Controller ve Agent<\/h2>\n<p>Jenkins iki bile\u015fenden olu\u015fur:<\/p>\n<ul>\n<li><strong>Controller (eski ad\u0131yla master):<\/strong> Web aray\u00fcz\u00fcn\u00fc sunar, pipeline tan\u0131mlar\u0131n\u0131 ve i\u015f kuyru\u011funu y\u00f6netir, sonu\u00e7lar\u0131 saklar. Do\u011frudan build i\u015flerini \u00e7al\u0131\u015ft\u0131rmak yerine bu i\u015fi agent&#8217;lara devretmesi \u00f6nerilir.<\/li>\n<li><strong>Agent (eski ad\u0131yla slave):<\/strong> As\u0131l build\/test\/deploy i\u015flerinin \u00e7al\u0131\u015ft\u0131\u011f\u0131 makine veya container. Bir controller&#8217;a birden fazla agent ba\u011flanabilir, her biri farkl\u0131 bir i\u015fletim sistemi veya ara\u00e7 setiyle donat\u0131labilir.<\/li>\n<\/ul>\n<h2>Jenkins&#8217;i Docker container olarak \u00e7al\u0131\u015ft\u0131rmak<\/h2>\n<p>Jenkins&#8217;in resmi imaj\u0131, kendisini de h\u0131zl\u0131ca aya\u011fa kald\u0131rman\u0131z\u0131 sa\u011flar. Docker imajlar\u0131 build edebilmesi i\u00e7in ana makinenin Docker soketini container i\u00e7ine ba\u011flamam\u0131z gerekir:<\/p>\n<pre><code>docker volume create jenkins_home\n\ndocker run -d --name jenkins \\\n  -p 8080:8080 -p 50000:50000 \\\n  -v jenkins_home:\/var\/jenkins_home \\\n  -v \/var\/run\/docker.sock:\/var\/run\/docker.sock \\\n  -v $(which docker):\/usr\/bin\/docker \\\n  --group-add $(stat -c '%g' \/var\/run\/docker.sock) \\\n  jenkins\/jenkins:lts-jdk17<\/code><\/pre>\n<p>\u0130lk a\u00e7\u0131l\u0131\u015fta Jenkins, konsol loglar\u0131na bir kurulum \u015fifresi yazd\u0131r\u0131r (<code>docker logs jenkins<\/code> ile g\u00f6rebilirsiniz); taray\u0131c\u0131dan <code>localhost:8080<\/code>&#8216;a gidip bu \u015fifreyle kurulum sihirbaz\u0131n\u0131 tamamlars\u0131n\u0131z ve \u00f6nerilen eklentileri (Docker Pipeline dahil) y\u00fckletirsiniz.<\/p>\n<div class=\"callout\">\n  <span class=\"glyph\">i<\/span><\/p>\n<p><code>\/var\/run\/docker.sock<\/code>&#8216;u container i\u00e7ine ba\u011flamak, Jenkins container&#8217;\u0131na ana makinenin Docker daemon&#8217;\u0131n\u0131 do\u011frudan kontrol etme yetkisi verir \u2014 pratikte bu, o container&#8217;\u0131n host \u00fczerinde neredeyse root yetkisiyle i\u015flem yapabilece\u011fi anlam\u0131na gelir. Production&#8217;da bu riski azaltmak i\u00e7in Jenkins&#8217;i izole, g\u00fcvenilir bir sunucuda \u00e7al\u0131\u015ft\u0131r\u0131n ve container&#8217;a eri\u015fimi k\u0131s\u0131tlay\u0131n; alternatif olarak <a href=\"https:\/\/konteynerium.com\/index.php\/2026\/06\/26\/rootless-container-nedir-neden-kullanmalisiniz\/\">rootless<\/a> bir Docker-in-Docker (DinD) kurulumu da de\u011ferlendirilebilir.<\/p>\n<\/div>\n<h2>Jenkinsfile: pipeline&#8217;\u0131 kod olarak tan\u0131mlamak<\/h2>\n<p>Jenkins&#8217;te bir pipeline, projenizin k\u00f6k\u00fcne konan bir <code>Jenkinsfile<\/code> ile tan\u0131mlan\u0131r (GitHub Actions&#8217;taki <code>.github\/workflows\/*.yml<\/code>&#8216;e kar\u015f\u0131l\u0131k gelir). Declarative syntax en okunakl\u0131 ve \u00f6nerilen y\u00f6ntemdir:<\/p>\n<pre><code>pipeline {\n    agent any\n\n    environment {\n        IMAGE_NAME = 'kullanici-adi\/benim-api'\n        DOCKERHUB_CRED = credentials('dockerhub-token')\n    }\n\n    stages {\n        stage('Checkout') {\n            steps {\n                checkout scm\n            }\n        }\n\n        stage('Build') {\n            steps {\n                sh 'docker build -t $IMAGE_NAME:$BUILD_NUMBER .'\n            }\n        }\n\n        stage('Test') {\n            steps {\n                sh 'docker run --rm $IMAGE_NAME:$BUILD_NUMBER npm test'\n            }\n        }\n\n        stage('Zafiyet Taramas\u0131') {\n            steps {\n                sh 'trivy image --severity HIGH,CRITICAL --exit-code 1 $IMAGE_NAME:$BUILD_NUMBER'\n            }\n        }\n\n        stage('Push') {\n            steps {\n                sh '''\n                    echo $DOCKERHUB_CRED_PSW | docker login -u $DOCKERHUB_CRED_USR --password-stdin\n                    docker push $IMAGE_NAME:$BUILD_NUMBER\n                    docker tag $IMAGE_NAME:$BUILD_NUMBER $IMAGE_NAME:latest\n                    docker push $IMAGE_NAME:latest\n                '''\n            }\n        }\n\n        stage('Deploy') {\n            steps {\n                sshagent(['prod-sunucu-ssh']) {\n                    sh '''\n                        ssh kullanici@prod-sunucu.ornek.com \\\n                          \"docker pull $IMAGE_NAME:latest && docker compose up -d --no-deps api\"\n                    '''\n                }\n            }\n        }\n    }\n\n    post {\n        failure {\n            slackSend channel: '#deploy', message: \"Build #${BUILD_NUMBER} ba\u015far\u0131s\u0131z oldu.\"\n        }\n    }\n}<\/code><\/pre>\n<p>Her <code>stage<\/code>, Jenkins aray\u00fcz\u00fcnde ayr\u0131 bir kutu olarak g\u00f6r\u00fcn\u00fcr \u2014 hangi ad\u0131m\u0131n ne kadar s\u00fcrd\u00fc\u011f\u00fcn\u00fc ve nerede ba\u015far\u0131s\u0131z oldu\u011funu tek bak\u0131\u015fta g\u00f6rebilirsiniz. <code>credentials()<\/code> fonksiyonu, Jenkins&#8217;in kendi \u015fifrelenmi\u015f kimlik bilgisi deposundan (Manage Jenkins \u2192 Credentials) de\u011fer okur; parolalar hi\u00e7bir zaman Jenkinsfile i\u00e7ine a\u00e7\u0131k yaz\u0131lmaz.<\/p>\n<h2>Webhook ile otomatik tetikleme<\/h2>\n<p>Her kod push&#8217;unda pipeline&#8217;\u0131n otomatik ba\u015flamas\u0131 i\u00e7in GitHub reponuzda bir webhook tan\u0131mlan\u0131r: <strong>Settings \u2192 Webhooks \u2192 Add webhook<\/strong>, Payload URL&#8217;e <code>http:\/\/jenkins-sunucunuz:8080\/github-webhook\/<\/code> yaz\u0131l\u0131r. Jenkins taraf\u0131nda ilgili proje i\u00e7in <strong>&#8220;GitHub hook trigger for GITScm polling&#8221;<\/strong> se\u00e7ene\u011fi i\u015faretlenir. Art\u0131k her push, saniyeler i\u00e7inde yeni bir build tetikler \u2014 elle &#8220;Build Now&#8221; t\u0131klamaya gerek kalmaz.<\/p>\n<h2>Jenkins vs GitHub Actions: hangisi ne zaman?<\/h2>\n<table>\n<thead>\n<tr>\n<th>Kriter<\/th>\n<th>Jenkins<\/th>\n<th>GitHub Actions<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Bar\u0131nd\u0131rma<\/td>\n<td>Kendi sunucunuz (self-hosted)<\/td>\n<td>GitHub&#8217;\u0131n bulut altyap\u0131s\u0131 (veya self-hosted runner)<\/td>\n<\/tr>\n<tr>\n<td>Kurulum y\u00fck\u00fc<\/td>\n<td>Y\u00fcksek \u2014 sunucu, g\u00fcncelleme, eklenti y\u00f6netimi size ait<\/td>\n<td>S\u0131f\u0131r \u2014 GitHub reposu varsa haz\u0131r<\/td>\n<\/tr>\n<tr>\n<td>Esneklik \/ eklenti<\/td>\n<td>\u00c7ok y\u00fcksek (1800+ eklenti)<\/td>\n<td>Marketplace action&#8217;lar\u0131 ile orta-y\u00fcksek<\/td>\n<\/tr>\n<tr>\n<td>Maliyet<\/td>\n<td>Sunucu maliyeti size ait, yaz\u0131l\u0131m \u00fccretsiz<\/td>\n<td>Public repo \u00fccretsiz; private repo&#8217;da dakika bazl\u0131 \u00fccretlendirme<\/td>\n<\/tr>\n<tr>\n<td>Karma\/\u00f6zel altyap\u0131<\/td>\n<td>Do\u011fal destek<\/td>\n<td>Self-hosted runner ile m\u00fcmk\u00fcn, ek kurulum gerekir<\/td>\n<\/tr>\n<tr>\n<td>\u00d6\u011frenme e\u011frisi<\/td>\n<td>Daha dik (Groovy tabanl\u0131 Jenkinsfile, plugin y\u00f6netimi)<\/td>\n<td>Daha d\u00fcz (YAML, geni\u015f haz\u0131r action k\u00fct\u00fcphanesi)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>K\u00fc\u00e7\u00fck-orta \u00f6l\u00e7ekli, GitHub&#8217;da bar\u0131nan projeler i\u00e7in GitHub Actions genellikle daha az s\u00fcrt\u00fcnmeyle i\u015fe yarar. Kurumsal, karma altyap\u0131l\u0131 veya veri gizlili\u011fi gereksinimi y\u00fcksek ortamlarda Jenkins&#8217;in esnekli\u011fi ve tam kontrol\u00fc \u00f6ne \u00e7\u0131kar. \u0130kisi birbirini d\u0131\u015flamaz \u2014 baz\u0131 ekipler basit projelerde Actions&#8217;\u0131, kritik\/\u00f6zel altyap\u0131 gerektiren projelerde Jenkins&#8217;i bir arada kullan\u0131r.<\/p>\n<p>Pipeline art\u0131k her push&#8217;ta otomatik \u00e7al\u0131\u015f\u0131yor. Bir sonraki ad\u0131m, sunucular\u0131n\u0131z\u0131n kendisini de elle de\u011fil, tutarl\u0131 ve tekrarlanabilir \u015fekilde yap\u0131land\u0131rmak \u2014 bunu bir sonraki yaz\u0131da, Ansible ile otomasyon ba\u015fl\u0131\u011f\u0131 alt\u0131nda ele al\u0131yoruz.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jenkins&#8217;i bizzat bir Docker container&#8217;\u0131 olarak aya\u011fa kald\u0131r\u0131p, Jenkinsfile ile build \u2192 test \u2192 zafiyet taramas\u0131 \u2192 push \u2192 deploy ad\u0131mlar\u0131n\u0131 otomatikle\u015ftiren ger\u00e7ek bir pipeline kuruyoruz; GitHub Actions ile kar\u015f\u0131la\u015ft\u0131rmal\u0131.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"seviye":[9],"class_list":["post-222","post","type-post","status-publish","format-standard","hentry","category-production-uygulamalar","seviye-ileri"],"_links":{"self":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts\/222","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/comments?post=222"}],"version-history":[{"count":1,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts\/222\/revisions"}],"predecessor-version":[{"id":581,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/posts\/222\/revisions\/581"}],"wp:attachment":[{"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/media?parent=222"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/categories?post=222"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/tags?post=222"},{"taxonomy":"seviye","embeddable":true,"href":"https:\/\/konteynerium.com\/index.php\/wp-json\/wp\/v2\/seviye?post=222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}