DevSecOps Deploying a Netflix Clone CI/CD Project on AWS EKS
DevSecOps CI-CD Netflix Project

DevSecOps CI-CD Netflix PROJECT
Bu makalemizde Netflix Platformunun ufak bir replicasını kod seviyesinde Güvenlik analizinden geçirecek sonrasında bir docker image yaratacağız ve bu yarattığımız imajı güvenlik analizinden geçirip cloud ve local olmak üzere birden fazla repoya gönderip Kubernetes üzerinde dağıtımını gerçekleştiriyor olacağız.
Adımlar
Bu makalemizde aşağıdaki adımları izleyeceğiz.
- Step 1a — Create an Ubuntu 24.04 T2 Large Instance
- Step 1b — Install Jenkins, Docker,Trivy,Sonarqube on Container using Docker,Docker-Scout
- Step 1c — Install Plugins like JDK, Sonarqube Scanner, OWASP Dependency Check
- Step 1d — Configure Sonarqube Server in Manage Jenkins
- Step 2a — TMBD Account configuration for API
- Step 2b — Create a Pipeline Project in Jenkins using a Declarative Pipeline
- Step 3a — Docker Image Build and Push
- Step 3b — Deploy the image using Docker
- Step 4a —-install&Configure Nexus Repostrory
- Step 4b — Docker host configure Nexus Repostroy
- Step 5a — Gmail Configuration
- Step 5 — AWS EKS Kubernetes setup
- Step 6 — Configuration Kubernets to Jenkins
- Step 7 — Using jenkins Deploy to application on Kubernetes
Ön Gereksinimler
Jenkins Server için :
- AWS EC2 t2.Large Machine
- On Premis |Os:Ubuntu 24.04 | Cpu:2 Core| Ram:8GB
- Security Group Port: 8080(Jenkins),8081,8082,8083,9000(Sonarqube),22(ssh)
Kubernetes Cluster için:
- AWS EKS Kubernetes için AWS cli aracı
Step 1 → Jenkins Server Kurulumu
AWS üzerinde 1 adet ubuntu “T2 Large Instance” oluşturuyoruz.
Not : Eğer on prem vm üzerinde kurulum yapıyorsanız Min CPU:2 core Ram:8GB
Aşağıdaki Linkte yer alan “Install Jenkins on Ubuntu” kod bloğunu yukarıdaki bu bölüme yapıştırarak tüm kurulumu otomatik hale getirip tüm gerekli paketleri sunucumuza yüklüyoruz.
Github: https://github.com/serdarbayram01/Code_Store
işlem bitince makinemiz aşağıdaki gibi hazır olacak.
Yukarıdaki Linkte yer alan komut setini AWS EC2 makinemi oluştururken “User data” bölümüne giriyorum böylelikle bu işlemleri makineye bağlanıp tek tek çalıştırmamıza gerek kalmadan AWS bizim için makine kurulum sırasında hallediyor olacak.
Eğer On-prem bir yapı kurllanıyorsanız komutları cli üzerinden tek tek çalıştırarark kurabilirsiniz.
AWS Security group (Firwall)
Firwall üzerinde yada AWS Security Group üzerinden aşağıdaki portların açık olması gerekmektedir .
Port: 8080,8081,8082,8083,9000,22,8
Jenkins Configuration
adresine giderek sunucumuza bağlanıyoruz aşağıdaki sayfa bizi karşılayacak.
cat /var/lib/jenkins/secrets/initialAdminPassword
Yukarıdaki komutla jenkins için oluşturulmuş parolayı alıp Jenkinsimize login oluyoruz.
install Suggested Plugin seçeneği ile devam ediyoruz.
Kendime bir admin hesabı oluşturacağım ekran geliyor buraya hesap bilgilerimi giriyorum.
Paket Versiyon Check
birçok paket kurulumu yaptık aşağıdaki komutlarla jenkins serverımıza yüklediğimiz paketlerin kontrolünü yapıyoruz.
docker -v docker compose --version trivy --version terraform --version /usr/bin/java --version jenkins --version aws --version kubectl version --client eksctl version
docker ps -a
Bu komutla aktif durumda olan containerlarımı görüntülüyorum göründüğü gibi sonarqube serverım da container olarak çalışır durumda.
Docker-Scout
Docker Inc. tarafından geliştirilen ve yazılım konteynerleri ile ilgili güvenlik, uyumluluk ve yazılım tedarik zinciri risklerini analiz etmeye odaklanan bir araçtır.
Docker Scout, özellikle Docker konteynerleri için yazılım bileşenlerini tarar ve potansiyel güvenlik açıklarını, lisans sorunlarını veya diğer riskleri belirler.
Süreçlerimizde ek bir güvenlik analiz aracı olarak süreçlerimize bu aracı da entegre edeceğiz bunun için aşağıdaki komutları kullanarak “ubuntu” userımızla komutlarımızı çalıştırıyoruz burada user “ubuntu” olmalı burayı atlarsanız CICD sürecinde docker scout u çalıştırmada sorun yaşarsınız.
#Docker hub portalımıza cli üzerinden login oluyoruz. docker login `Give Dockerhub credentials here`
curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh sh install-scout.sh
Yukarıdaki komutlar sonrası çıktımız aşağıdaki gibi olacaktır.
Username: serdarbayram Password: ************ WARNING! Your password will be stored unencrypted in /home/ubuntu/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded ubuntu@ip-172-31-43-76:~$ curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh sh install-scout.sh
Sonarqube Login
adresine girerek sonarqube serverımıza bağlanıyoruz.
user name :admin Password :admin
Yeni parola belirliyoruz.
Login olduktan sonra bizi Sonarqube ekranımız karşılıyor.
Sonarqube ilk adım bu kadar.
Jenkins Eklenti Kurulumları
Labımız için jenkins serverda olması gereken eklentilerin kurulumlarını yapıyoruz.
Manage Jenkins→Plugin yolunu takip ederek aşağıdaki pluginleri yüklüyoruz.
- OWASP Dependency-Check
- Eclipse Temurin
- Sonarqube Scanner
- Pipeline: Stage View
- Blue Ocean
install diyerek kurulumu başlatıyorum.
Jenkins Tools Configuration
Jenkins Manage →Tools →Jdk
“jdk17” adını veriyoruz burada verdiğimiz isim oldukça önemli çünkü pipeline yazarken bu isimleri kullanacağız.
OWASP Dependency Check Plugins
Jenkins Manage →Tools→Dependency-Check installations
“DP-check” adını veriyoruz burada verdiğimiz isim oldukça önemli çünkü pipeline yazarken bu isimleri kullanacağız.
SonarQube Scanner Config
Jenkins Manage →Tools→SonarQube Scanner installations
“sonar-scanner” adını veriyoruz burada verdiğimiz isim oldukça önemli bir sonraki adımda sonar qube serverımızın tanımlarını yaparken bu adı kullanacağız.
Sonarqube Configuration
http://jenkins-server-ip:9000 adresine giderek sonarqube serverımıza bağlanıyoruz.
Sağ üst bölümdeki “Administrator” →My Account yolunu takip ediyoruz.
“Security” bölümüne geliyoruz ve jenkins serverımızın sonarqube ile bağlantı kurup analizler için kullanacağı “jenkins” adında token credentialı “Generate” diyerek oluşturuyoruz.
Bize vermiş olduğu keyi bir yere not ediyoruz bunu daha sonra kullanacağız.
Webhook Configuration
SonarQube webhook’ları, bir yazılım projesinin kod kalitesi analizinin tamamlandığına dair bir web adresine bildirim göndermek için kullanılan bir mekanizmadır. Bu bildirimler, genellikle bir HTTP POST isteği şeklinde gönderilir ve içerisinde analiz sonuçlarına dair JSON formatında veriler bulunur. Bu sayede, SonarQube’da gerçekleştirilen analizlerin sonuçları, başka sistemlere veya araçlara anında iletilebilir ve otomatik işlemler tetiklenebilir.
Administration→ Configuration→Webhooks
Create Diyerek webhook umuzu oluşturuyoruz.
Jenkins serverımızın public ip adresini bu alana yazarak aşağıdaki formatta giriyoruz.
#in url section of quality gate http://jenkins-public-ip:8080/sonarqube-webhook/
Jenkins Sonarqube credential
“Jenkins Manage → Credential” Menüsüne gidiyoruz.
Global seçeneğini seçerek Devam ediyoruz.
“Secret txt” seçeneğini seçiyoruz ve sonarqube için oluşturduğumuz token bilgisini buraya giriyoruz.
ID bölümünü “sonar-cred” olarak giriyoruz burası oldukça önemli çünkü pipeline bölümünde bu isimle çağıracağız.
TMBD API yapılandırma
The Movie Database (TMDb), filmler, diziler ve bu yapımlarla ilgili oyuncular, yönetmenler ve yapım ekipleri hakkında kapsamlı bilgiler sunan kullanıcı katkılı bir çevrimiçi platformdur. İçeriklerin fragmanlarından posterlere, oyuncu kadrolarından hikâye özetlerine kadar pek çok detay sunar.
Sunduğu API sayesinde geliştiriciler, uygulama ve web sitelerinde TMDb veritabanındaki bilgileri kullanabilir.
Bizde burada elimizdeki Netflix clonu için bu Platformda bir hesap yaratıp API Keyi alacağız ve kodumuzu dockerize ederken bu api keyi kullanacağız.
Mail hesabınızla kayıt olup login olduğunuzda aşağıdaki gibi bir sayfa sizi karşılayacak.
Yukarıdaki ekranda profil resminize takılayıp Setting menüsüne gidiyoruz.
Karşımıza gelen sayfada API sekmesini bulup buradaki “API key” bir yere not ediyoruz.
Bu aldığımız API key’i Docker imajı yaratırken Environment parametresi olarak kullanacağız.
Bu portaldan alacağımız bilgiler bu kadar.
Jenkins sonarqube integration
“Jenkins Manage → System” Menüsüne gidiyoruz.
“Add sonarqube” diyerek sonarqube serverımıza ait yukarıda tanımladığımız bilgileri giriyoruz.
Name =”sonar-server” olarak giriyoruz.
Server URL = http://localhost:9000 # şeklinde girdim çünkü sonarqube ile jenkins serverım aynı makine, Jenkins localhost u 9000 portundan çağırdığında direk sonarqube containerına gidecek.
server authentication token : buraya credential bölümünde girdiğimiz “sonar-cred” hesabını seçiyoruz.
Kaydedip çıkıyoruz.
Step2 → Projeyi Oluşturma
“Dashboard → New Item“ yolunu izleyerek aşağıdaki ekranda Projemize bir isim veriyoruz “Netflix” ve pipeline ı seçerek projemizi yaratıyoruz.
pipeline{ agent any tools{ jdk 'jdk17' } environment { SCANNER_HOME=tool 'sonar-scanner' } stages { stage('clean workspace'){ steps{ cleanWs() } } stage('Checkout From Git'){ steps{ git branch: 'main', url: 'https://github.com/serdarbayram01/Netflix.git' } } stage("Sonarqube Analysis "){ steps{ withSonarQubeEnv('sonar-server') { sh ''' $SCANNER_HOME/bin/sonar-scanner -Dsonar.projectName=Netflix \ -Dsonar.projectKey=Netflix ''' } } } stage("quality gate"){ steps { script { waitForQualityGate abortPipeline: false, credentialsId: 'sonar-cred' } } } stage("TRIVY File scan"){ steps{ sh "trivy fs . > trivy-fs_report.txt" } } stage('Docker Scout FS') { steps { script{ withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker'){ sh 'docker-scout quickview fs://. > scout_quickview_file_report.html' sh 'docker-scout cves fs://. > scout_cves__file_report.txt' } } } } stage("OWASP Dependency Check"){ steps{ dependencyCheck additionalArguments: '--scan ./ --format XML ', odcInstallation: 'DP-check' dependencyCheckPublisher pattern: '**/dependency-check-report.xml' } } } }
işlem sonucu Sonarqube baktığımızda aşağıdaki gibi bir analiz ekranı görüyor olacağız.
ilk çalıştırdığınızda bu işlem yaklaşık 30~60 dk arası sürecektir. Owasp DB sini indirmek bağlantı hızı ve makine performansınıza göre değişmektedir.
Step 3 → Docker Image Build and Push
Sistemimize Docker aracını yüklememiz gerekiyor, Dashboard → Manage Plugins → Available plugins→ Docker‘ı arayın ve bu eklentileri yükleyin
- Docker
- Docker Commons
- Docker Pipeline
- Docker API
- docker-build-step
Dashboard → Manage Jenkins → Tools
Menüsüne gidiyoruz ve docker’ın hangi versiyonla çalıştırılacağını(latest) belirliyoruz.
Docker hub (https://hub.docker.com/) hesabımızı Jenkins serverımıza tanımlıyoruz.
Dashboard → Manage Jenkins → Credential → (Global)
Burada docker hub hesap bilgilerimi girerek “docker-cred” adıyla kayıt ediyorum.
Jobımıza giderek config menüsünü açıyoruz ve aşağıdaki kodları kendi repo ve hesap bilgilerinize göre düzenleyerek pipeline’ımıza ekliyoruz.
Dahsboard→ Netflix→Configure
stage('Docker Build & Push') { steps { script { withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker') { sh ''' docker build --build-arg TMDB_V3_API_KEY=d79a2ee6fafe35d7126de38adcf1df08 \ -t serdarbayram/netflix:latest . docker push serdarbayram/netflix:latest ''' } } } }
Yukarıdaki kodu incelediğinizde aşağıdaki satırda “TMDB_V3_API_KEY=” yazan yerede TMBD den aldığımız API key’i giriyoruz. Böylece uygulamamız içerikleri TMBD den çekerek güncelleyebilecek.
docker build --build-arg TMDB_V3_API_KEY=d79a2ee6fafe35d7126de38adcf1df08 -t serdarbayram/netflix:latest .
Kodumuzu çalıştırdığımızda imajımız “serdarbayram/netflix:latest” adında oluşturulmuş olacak. Tüm işlemleri başarıyla tamamladığınızda aşağıdaki gibi tamamlanmış pipline ı göreceksiniz.
aşağıdaki şekilde imajımızın hazır hale geldiğini görebilirsiniz.
Docker İmage Security Check
Buraya kadar olan bölümde uygulamamızdaki kodları güvenlik analizden geçirdik şimdi Docker imajımızı Güvenlik analizinden geçirmeye geldi.
Bunun için opensource olan “Trivy” ve ”Docker-Scout” uygulamalarını kullanacağız.
Jenkins serverımızı kurarken “Trivy” aracını otomatik kuruluma eklemiştik bunun için birşey yapmayacağız fakat Docker-scout içinde makalenin başında kurulum adımlarını anlatmıştım. Bu yüzden şu an yapmamız gereken tek şey pipeline a bu config eklemesini yapmak olacak.
stage('Trivy Image Scan') { steps { script { sh ''' echo "Trivy ile serdarbayram/netflix:latest imajı taranıyor..." trivy image serdarbayram/netflix:latest ''' } } } stage('Docker Scout Image') { steps { script { withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker') { sh 'docker-scout quickview serdarbayram/netflix:latest > scout_quickview_report.txt' sh 'docker-scout cves serdarbayram/netflix:latest > scout_cves_report.txt' sh 'docker-scout recommendations serdarbayram/netflix:latest > scout_recommendations_report.txt' } } } }
Yukarıdaki kodu pipeline a ekleyip job umuzu çalıştırdığımızda aşağıdaki şekilde işlemimiz in başarıyla tamamlandığını göreceğiz.
Yapılan “Docker Scout” analizinin dosyalarını aşağıdaki dizinde bulabilirsiniz.
# /var/lib/jenkins/workspace/<Project Name> cd /var/lib/jenkins/workspace/Netflix
Nexus repository Kurulumu
Nexus Repository, Sonatype tarafından geliştirilmiş bir binaries repository manager (ikili depo yöneticisi) olup, yazılım geliştirme ekiplerinin bağımlılıkları, artefaktları ve Docker imajları gibi verileri merkezi olarak depolayıp yönetmesini sağlar.
Maven, Gradle, npm, PyPI, Docker, Helm, Yum gibi popüler formatlardaki verileri destekleyen Nexus, bağımlılıkların önbelleğe alınmasını, güvenliğini ve dağıtımını kolaylaştırır. Harici depolar için proxy işlevi sunarak ağ trafiğini optimize eden Nexus, CI/CD süreçleriyle entegre çalışarak yazılım geliştirme sürecini hızlandırır ve güvenli hale getirir. Hem açık kaynaklı hem de ticari sürüm (Pro) seçenekleriyle sunulan Nexus, açık kaynak dünyasında güçlü repo çözümlerinden biridir.
Biz bu projede Nexus’u local repostory olarak kullanıp docher hub dışında 2. bir repoya daha imajlarımızı göndereceğiz. Böylelikle imajlarımızı localde de kullanabilme esnekliğine kavuşacağız.
Bu projede makalenin çok uzamaması için nexus u docker container olarak kuracağım eğer production ortamında kullanmak istiyorsanız bunu ayrı bir VM üzerinde konumlandırmanızı tavsiye ederim.
Aşağıdaki komutu çalıştırarak Jenkins serveırmız üzerine Nexus3 kurulumunu yapıyoruz.
docker run -d --name nexus \ -p 8081:8081 \ -p 8083:8083 \ --restart always \ sonatype/nexus3
Nexus serverımız 8081 portundan yayın yapacak fakat bu proje için oluşturacağım repoya 8083 portundan erişim sağlayacağım bu yüzden bu portu açtım.
Son çıktımız yukarıdaki gibi olacak nexus serverıma http://jenkinsServerIp:8081 yazarak erişim sağlıyorum.
Aşağıdaki komutla nexus sıfırlama parolasını alıyoruz username“ admin” pass:”**” aldığımız parola . Parolamızla giriş yaptıktan sonra login oluyoruz ve kendimize ait admin parolamızı belirliyoruz.
docker exec nexus cat /nexus-data/admin.password
Nexus Repostory Yaratma
Yukarıdaki çarka tıklıyoruz ve Create repostory diyoruz.
Biz docker image yükleyeceğiz (docker hosted) ı seçiyoruz.
Aşağıdaki bölümleri doldurarak
Name:Netflix
Http:8083
Enable Docker Vi API:
Seçenekelerini doldurarak kayıt edip repomuzu yaratıyoruz.
Sol Menüden “Realm” menüsüne geliyoruz ve “docker Bearer Token Realm” seçeneğini sağ tarafa atıyoruz.
Nexus Serverdaki config işlemlerimiz bu kadar.
Jenkins ve Docker hostumuz aynı makine docker repostory’nin nexus serverımıza ulaşabilmesi için bu reponun güvenilir bir adres olması gerekiyor bunun içinde Nexus serverın ssl sertifika ile https üzerinden yayın yapması gerek fakat bu makalenin konusu bu olmadığ için biz nexus serverımızı Docker repostorysine ip adresi olarak güvenlilen repolara ekleyeceğiz Böylece Docker üzerinde oluşturduğumuz imajları nexus serverımıza yollayabilir olacağız.
Aşağıdaki komutla dosyamızı yaratıyoruz.
sudo nano /etc/docker/daemon.json
Aşağıdaki satırları yapıştırıyoruz buradaki ip adreslerini nexus serverımızın ip adresi ile değiştirmeniz gerekiyor.
{ "insecure-registries": [ "34.242.253.35:8083", "34.242.253.35:8081" ] }
Bu işlem sonrası docker deamon servisimizi restart ediyoruz.
sudo systemctl restart docker
şimdi Nexus serverımıza CLI üzerinden bir bağlantı yaparak az önce açtığımız 8083 portu üzerinden bağlantı kontrolü yapıyoruz.
#sudo docker login -u admin nexus_public_dns_name:8085 sudo docker login -u admin 34.242.253.35:8083
Nexus parolamı girdiğimde aşağıdaki gibi Login succeeded bilgisini alacağız.
Eğer buraya kadar hata almadan geldiysek artık Nexus repostory mize push işlemi gerçekleştirebiliriz.
image Build
Eğer kodunuzu manual şekilde derleyip build edecekseniz aşağıdaki komutu kullanabilirsiniz.
#sudo docker build . -t nexus_public_dns_name:8085/Netflix sudo docker build . -t 34.242.253.35:8083/Netflix
imaj Tag
Fakat biz yukarıdaki adımlarda zaten imajımızı dockerhub a gönderirken “serdarbayram/netflix:latest” olarak yaratmıştık bu işlem için imajımızı yeniden tag leyeceğiz ve aşağıdaki komutu kullanacağız.
docker tag serdarbayram/netflix 34.242.253.35:8083/netflix:latest
image push
Nexus repoya Manuel ogin oluyoruz karşımıza gelen ekranda “admin”,”password” bölümlerini gidiyoruz.
docker login 34.242.253.35:8083
succeeded logunu gördüysek portumuz çalışıyor ve repomuza login olabilmişiz demektir artık imajımızı aşağıdaki komutu girerek push edebiliriz.
docker push 34.242.253.35:8083/netflix:latest
komutumuz çalıştıktan sonra yukarıdaki gibi imajımızı pushladığını görebilirsiniz. Nexus panelimize gidip kontrol sağladığımızda imajımızı aşağıdaki şekilde görüntüleyeceksiniz.
Nexus Jenking integration
Nexus sunucumuza başarılı bir şekilde imajlarımızı gönderebiliyoruz bunu güvenli şekilde Jenkins pipeline eklememiz gerekiyor bunun için Jenkins serverımızda Manage→Credential altında jenkins hesap bilgilerimizi giriyoruz.
Jenkins üzerinde yarattığımız hesaplar aşağıdaki gibi görünüyor olmalı.
Jenkins Netflix porjesine gidiyoruz ve pipeline a aşağıdaki kodu ekliyoruz.
Burada dikket etmeniz gereken yer “34.242.253.35:8083” olarak kendi nexus serverımın adresini girdiğim bölümleri değiştirmelisiniz.
stage('Nexus Image Push') { steps { script { withCredentials([usernamePassword(credentialsId: 'nexus-cred', usernameVariable: 'NEXUS_USER', passwordVariable: 'NEXUS_PASS')]) { sh """ echo $NEXUS_PASS | docker login -u $NEXUS_USER --password-stdin https://54.217.41.64:8083 docker tag serdarbayram/netflix 54.217.41.64:8083/netflix:latest docker push 54.217.41.64:8083/netflix:latest """ } } } }
Bu düzenleme sonrası job umuzu çalıştırdığımızda pipelinemızın başarıyla tamamlandığını görebilirsiniz.
Nexus serverımıza baktığımızda imajımızın push olduğunu ve saat bilgisini görebilirsiniz.
Step 4 → Public Erişim
Aşağıda sarı ile belirttiğim portların SG üzerinde açık olup olmadığının kontrollerini yaptıktan sonra web sayfamıza erişim sağlayabiliriz .
Docker imaj Deploy
Yukarıdaki tüm adımlar bir uygulamanın imaj haline gelitirlmesi,Kod güvenlik analizi, imaj güvenlik analizi ve Ayrı bir repostory e aktarılması adımlarını içeriyordu artık imajımızın analizler sonrası güvenli olduğunu biliyoruz ve imajımızı docker hostumuz üzerinde deploy edeceğiz.
Bunun için jenkins pipeline a aşağıdaki komutları ekyerek uygulamamızı 8082 portundan publish edeceğiz
stage('Deploy to Container') { steps { sh 'docker rm -f netflix' sh 'docker run -d --name netflix -p 8082:80 serdarbayram/netflix:latest' } }
işlem tamamlandığında aşağıdaki şekilde pipeline ımızı görüntüleyebiliriz.
docker containerlarımı kontrol ettiğimde netflix imajımın yayınlandığını görebiliyorum.
http://jenkinsServerIp:8082 portundan sayfayı çağırdığımda aşağıdaki şekilde uygulamamı görüntülüyorum.
Email Notification
Pipelinedaki işlemlerimiz uzun süler alabilir yada her işlem sonrası alınan aksiyondan haberdar olmak isteyebilirsiniz bunun için jenkis job’umuz tamamlandığında sistemin bize mail göndererek Mail atmasını sağlayacağız.
Security Group Conf
Bu işlemi de Gmail hesabımız üzerinden yapacağız, gmail SMTS 465 portu üzerinden haberleşir bu sebeple jenkins serverımızında 465 portundan gelen isteklere yanıt vermesi gerekiyor Serverımızın dahil olduğu Security Group a 465 portunu ekliyoruz.
Gmail Account Config
Gmail hesabımızı açıyourz ve sağ üst bölümde ismimizin baş harfinin yer aldığı ikona tıklayıp ayarlara giriyoruz.
Soldan Security sağda açılan sayfada 2-step-Verification seçeneğine tıklayarak devam ediyoruz.
Not: Gmail Device application pass özelliğini kullanabilmeniz için hesabınızda 2 factor doğrulama ayarlarının yapılmış olması gerekiyor, Eğer sadece parola ile login seçeneği varsa bu fonksiyon karşınıza gelmeyecek yada sonraki menüleri getirmeyecektir .
Yukarıdaki ekranı en alta indirdiinizde “Application Password” Menüsü gelecek. Bir cihaz adı veriyoruz “Jenkins” verdim ben sonrasında aşağıdaki gibi bir kod veriyor sistem bize bu kodu bir yere not ediyoruz. Bu kodu şifre olarak kullanacağız.
Jenkins configuration
E-mail göndermek için “Email Extension Template” jenkins eklentisine ihtiyacımız var. Manage→Plugin bölümüne gidip indiriyoruz.
Manage→Credential Menüsüne giderek “Global” altında gmail hesabımız için hesap bilgilerini giriyoruz.
Hesap tanımı sonrası hesap listemi aşağıdaki şekilde olacak.
Manage→System Menüsüne
gidiyoruz.“Extended E-mail Notification” bölümüne geliyoruz ve aşağıdaki şekilde sunucu bilgileri ve mail hesap bilgilerini giriyoruz.
“E-mail Notification” bölümüne geliyoruz.
buradaki bilgileri aşağıdaki şekilde dolduruyoruz.
Email Test
girdiğimiz configleri doğrulamak için bir test yapıyoruz. mail adresimizi girerek “Test config” butonuna basıyoruz.
Test sonrası aşağıdaki gibi bir mail posta kutunuza gelecek
son olarak default Trigger altındaki aşağıdaki ayarlarıda aktif hale getiyoruz. Başrılı ve başarısız joblarda da bize mail atacak sistem.
Jenkins pipeline a aşağıdaki komut bloğunu ekliyoruz.
post { always { emailext( attachLog: true, subject: "'${currentBuild.result}'", body: """ <html> <body> <div style="background-color: #FFA07A; padding: 10px; margin-bottom: 10px;"> <p style="color: white; font-weight: bold;">Project: ${env.JOB_NAME}</p> </div> <div style="background-color: #90EE90; padding: 10px; margin-bottom: 10px;"> <p style="color: white; font-weight: bold;">Build Number: ${env.BUILD_NUMBER}</p> </div> <div style="background-color: #87CEEB; padding: 10px; margin-bottom: 10px;"> <p style="color: white; font-weight: bold;">URL: ${env.BUILD_URL}</p> </div> </body> </html> """, to: 'AlicininMailAdresi@gmail.com', mimeType: 'text/html', attachmentsPattern: 'trivy-fs_report.txt' ) }
Burada “}” işaretlerine dikkat ediyoruz son kodu ekledikten sonra hemen altında 2 adet } işareti kalacak.
Job umuzu çalıştırdıktan sonra “Declarative Post Action” staging de success bir şekilde tamamlandığını görebilirsiniz.
gelen mail aşağıdaki gibi görünecektir.
trivy analiz ekini açtığınızda sonucu bu şekilde görüntüleyebilirsiniz.
Step 5 → EKS kurulumu
AWS console login
Cluster Kurulumunu cli üzerinden yapacağız ve tüm komutları “ubuntu” user hesabı üzerinden yapıyor olacağız bu adımdan sonraki kısımlarda “root” hesabında işlem yapmıyoruz çünkü bir sonraki adımda root hesabında yapılan AWS tanımı jenkins job üzerinde bize sorun çıkarıyor.
Ubuntu hesabına geçiyoruz.
sudo ubuntu
AWS cli ile yetkili bir hesapla login oluyoruz.
aws configure
Setup EKS
Step 01: Create EKS Cluster using eksctl
# Create Cluster eksctl create cluster --name=Lab-Cluster-1 \ --region=eu-west-1 \ --zones=eu-west-1a,eu-west-1b \ --without-nodegroup
# Get List of clusters eksctl get cluster
işlem tamamlandığında EKS panelimizde clusterımızı aşağıdaki gibi görünür olacak.
Step 02: Create & Associate IAM OIDC Provider for our EKS Cluster
eksctl utils associate-iam-oidc-provider \ --region eu-west-1 \ --cluster Lab-Cluster-1 \ --approve
Step 03: Create EC2 Keypair
Sanal Makineler için oluşturduğumuz bir keypair varsa bunu kullanabilirsiniz eğer yoksa yada yeni farklı birşey kullanmak isiyorsanız EC2 paneline gidip yeni bir key pair oluşturun. Oluşturduğunuz keypair EKS node makinelere gerektiğinde bağlantı için kullanılacak bu sebeple bir sonraki adımda bu key’i komut içerisinde belirteceğiz.
Ben oluşturmuş olduğum “Lab.pem” isimli key i kullanacağım
Step 04: Create Node Group with additional Add-Ons in Public Subnets
eksctl create nodegroup --cluster=Lab-Cluster-1 \ --region=eu-west-1 \ --name=Lab-cluster1-ng \ --node-type=t3.medium \ --nodes=2 \ --nodes-min=2 \ --nodes-max=4 \ --node-volume-size=20 \ --ssh-access \ --ssh-public-key=Lab \ --managed \ --asg-access \ --external-dns-access \ --full-ecr-access \ --appmesh-access \ --alb-ingress-access
Yukarıdaki komutu çalıştırdığımızda kuruluşumuz aşağıdaki gibi tamamlanmış olacak.
Step 05: Verify Cluster & Nodes
# List EKS clusters eksctl get cluster # List NodeGroups in a cluster eksctl get nodegroup --cluster=<clusterName> eksctl get nodegroup --cluster=Lab-Cluster-1 # List Nodes in current kubernetes cluster kubectl get nodes -o wide # Our kubectl context should be automatically changed to new cluster kubectl config view --minify
AWS Contex
AWS Contex bilgisini aşağıdaki komutla alıyoruz biz 1 EKS e bağlanacağımız ve “ubuntu”user hesabımız yetkili olduğu için aşağıdaki context bilgisini bir yerde kullanmayacağız bunu bilgi olarak ilerde lazım olursa diye not olarak ekledim.
kubectl config get-contexts
Tüm contex bilgisini görüntülemek için aşağıdaki komutu kullanabilirsiniz.
cat ~/.kube/config
Ubuntu user Config to Jenkins
yukarıdaki işlemlerde aws cli ı çalıştırırken ubuntu hesabını kurduk fakat jenkins root hesabı ile kuruldu dolayısıyla jenkins servisi kendi oluşturduğu “Jenkins” user’ı ile çalışıyor bunu ubuntu user ile değiştirmeliyiz ki Jenkins serverisi aws configlerini ubuntu user profili altından okuyabilsin.
Aşağıdaki komutla jenkins servisini hangi hesabın çalıştırdığını kontrol ediyoruz.
ps -awux | grep jenkins
Çıktı sonucunda da gördündüğü gibi jenkins hesabı görünüyor
Aşağıdaki dosyayı edtliyoruz “jenkins” yazan bölümleri “ubuntu” yapıyoruz.
nano /lib/systemd/system/jenkins.service
Aşağıdaki komutları çalıştırarak “ubuntu” kullanıcısına jenkins doysalarına erişmesi için gereken izinleri veriyoruz.
sudo chown -R ubuntu:ubuntu /var/lib/jenkins sudo chown -R ubuntu:ubuntu /var/cache/jenkins sudo chown -R ubuntu:ubuntu /var/log/jenkins sudo chown -R ubuntu:ubuntu /usr/share/jenkins sudo chown -R ubuntu:ubuntu /run/jenkins
Jenkins servisimizi restart ediyoruz.
sudo systemctl daemon-reload sudo systemctl restart jenkins
Servisimiz başladıktan sonra jenkins servisimizi tekrar kontrol ettiğimizde artık “ubuntu” hesabıyla çalıştığını görüyor olmalıyız.
ps -awux | grep jenkins
Jenkins pipeline a aşağıdaki kodları “Deploy to Container” stag ten hemen sonra ekliyoruz böylece tüm pipeline tamamlanınca “Declerative Post Action” bize tüm aşamaların raporunu atacak.
stage('Deploy to k8s') { steps { dir('Kubernetes') { sh 'kubectl apply -f deployment.yaml' sh 'kubectl apply -f service.yaml' sh 'kubectl apply -f ingress.yaml' sh 'kubectl get svc' } } } }
Bu düzenlemeden sonra pipeline ımızı çalıştırdığımızda aşağıdaki şekilde tüm aşamaların başarıyla tamamlandığını görebilirsiniz.
Mail adresinizi kontrol ettiğinizde tüm aşamaların çıktılarının mailinizin ekinde olduğunu görebilirsiniz.
EKS üzerinde aldığımız Loadbalance adresimize gittiğimizde sayfanın aşağıdaki gibi görüntülendiğini görebilirsiniz.
Jenkins File
pipeline { agent any tools { jdk 'jdk17' } environment { SCANNER_HOME = tool 'sonar-scanner' } stages { stage('Clean Workspace') { steps { cleanWs() } } stage('Checkout From Git') { steps { git branch: 'main', url: 'https://github.com/serdarbayram01/Netflix.git' } } stage('SonarQube Analysis') { steps { withSonarQubeEnv('sonar-server') { sh """ $SCANNER_HOME/bin/sonar-scanner \ -Dsonar.projectName=Netflix \ -Dsonar.projectKey=Netflix """ } } } stage('Quality Gate') { steps { script { timeout(time: 300, unit: 'SECONDS') { def qg = waitForQualityGate() if (qg.status != 'OK') { error "SonarQube Quality Gate failed: ${qg.status}" } } } } } stage('Trivy File Scan') { steps { sh "trivy fs . > trivy-fs_report.txt" } } stage('Docker Scout FS') { steps { script { withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker') { sh 'docker-scout quickview fs://. > scout_quickview_file_report.html' sh 'docker-scout cves fs://. > scout_cves__file_report.txt' } } } } stage('OWASP Dependency Check') { steps { dependencyCheck additionalArguments: '--scan ./ --format XML', odcInstallation: 'DP-check' dependencyCheckPublisher pattern: '**/dependency-check-report.xml' } } stage('Docker Build & Push') { steps { script { withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker') { sh """ docker build --build-arg TMDB_V3_API_KEY=d79a2ee6fafe35d7126de38adcf1df08 \ -t serdarbayram/netflix:latest . docker push serdarbayram/netflix:latest """ } } } } stage('Trivy Image Scan') { steps { sh """ echo "Trivy ile serdarbayram/netflix:latest imajı taranıyor..." trivy image --format table -o trivy_image_scan_report.txt serdarbayram/netflix:latest """ } } stage('Docker Scout Image') { steps { script { withDockerRegistry(credentialsId: 'docker-cred', toolName: 'docker') { sh """ docker-scout quickview serdarbayram/netflix:latest > scout_quickview_report.txt docker-scout cves serdarbayram/netflix:latest > scout_cves_report.txt docker-scout recommendations serdarbayram/netflix:latest > scout_recommendations_report.txt """ } } } } stage('Nexus Image Push') { steps { script { withCredentials([usernamePassword(credentialsId: 'nexus-cred', usernameVariable: 'NEXUS_USER', passwordVariable: 'NEXUS_PASS')]) { sh """ echo $NEXUS_PASS | docker login -u $NEXUS_USER --password-stdin https://3.250.171.35:8083 docker tag serdarbayram/netflix 3.250.171.35:8083/netflix:latest docker push 3.250.171.35:8083/netflix:latest """ } } } } stage('Deploy to Container') { steps { sh 'docker rm -f netflix || true' sh 'docker run -d --name netflix -p 8082:80 serdarbayram/netflix:latest' } } stage('Deploy to k8s') { steps { dir('Kubernetes') { sh 'kubectl apply -f deployment.yaml' sh 'kubectl apply -f service.yaml' sh 'kubectl get svc' } } } } post { always { emailext( attachLog: true, subject: "'${currentBuild.result}'", body: """ <html> <body> <div style="background-color: #FFA07A; padding: 10px; margin-bottom: 10px;"> <p style="color: white; font-weight: bold;">Project: ${env.JOB_NAME}</p> </div> <div style="background-color: #90EE90; padding: 10px; margin-bottom: 10px;"> <p style="color: white; font-weight: bold;">Build Number: ${env.BUILD_NUMBER}</p> </div> <div style="background-color: #87CEEB; padding: 10px; margin-bottom: 10px;"> <p style="color: white; font-weight: bold;">URL: ${env.BUILD_URL}</p> </div> </body> </html> """, to: 'serdarbayram01@gmail.com', mimeType: 'text/html', attachmentsPattern: 'trivy*,scout*,dependency-check-report.xml' ) } } }