https://buraksenyurt.com/Burak Selim Şenyurt - DevOps2024-01-21T22:16:34+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/docker-yerine-podman-pod-manager-kullanmakDocker Yerine Podman (Pod Manager) Kullanmak2020-12-27T09:14:00+00:00bsenyurt<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/40/anakinspod.png" alt="" align="right" />Heimdall üstünden birşeyler kurcalamak istediğimde yolum genellikle bir Docker imajı ile kesişiyor. Bakmak istediğim bir NoSQL veritabanı mı var, ELK üçlüsü mü gerekli, bir NGinx server ortamımı lazım ya da yeni bir servis için çalışma zamanımı hazırlamam gerekiyor... Hemen Docker kardeşimizin kapısını çalıyorum. Aslında bakarsanız Container teknolojileri denince çoğumuzun aklına Docker'dan başka bir şey gelmiyordur belki de. "Gerçekten de böyle mi?" diye düşündüğüm bir ara Docker'ın güçlü bir alternatifi olan Podman isimli ürünle karşılaştım ve onu biraz tanımaya karar verdim.</p>
<p>Esasen Docker tek ve vazgeçilmez bir container aracı olarak düşünülmemeli. Sonuçta Open Container Initiative tarafından belirlenmiş standartlara uyan araçlar mevcut. <a href="https://opencontainers.org/" target="_blank">Open Container Initiative</a>, bu tip araçlarda üç temel özelliğin olmasını vurguluyor. Container çalışma zamanı<em>(runtime)</em>, dağıtım stratejisi<em>(distribution)</em> ve baş aktör olarak da image<em>. </em>Podman bu standartlara uyan araçlardan birisi. Buna göre Podman ile hazırlanan imajlar Docker ile veya XYZ isimli başka bir Container ile de uyumlu oluyor <em>(Zaten stadartların amacı da bu değil mi? Farklı ürünlerin birbirleri yerine tercih edilip kullanılabilmesi için ortak bir yöntemler kılavuzu sunmak)</em></p>
<p>Red Hat tarafından açık kaynak olarak geliştirilen Podman özünde Pod<em>(Kubernetes'in en küçük işlem birimi olarak bahsi geçen lakin benim aklıma hep Anakin Skywalker'ın yarış aracını getiren)</em> sistemine dayanıyor. Dolayısıyla Podman ortamından Kubernetes üzerine göç etmek<em>(migration)</em> oldukça kolay. Pod içerisinde birden fazla Container kullanılabiliyor ve ayrıca Docker da olduğu gibi daemon ihtiyacı bulunmuyor. Zaten temel fark her ikisinin farklı mimari kullanmaları. Docker, client-server temelli bir mimariyi baz alıyor. Client görevi üstlenen CLI arabirimi<em>(ki biz onun komutlarını kullanıyoruz)</em> arka planda<em>(Server side)</em> image nesnesi inşa etmek ve container çalıştırmak gibi işleri üstlenen daemon ile iletişim halinde. CLI'ın Daemon ile olan bu iletişimi Root kullanıcı yetkilerine ihtiyaç duymakta.</p>
<p>Podman ise bunun aksine Root kullanıcı şart koşmuyor çünkü Daemonless bir mimari kullanmakta. Standart bir kullanıcı söz konusu ise onun için açılan özel çalışma sahası<em>(namespace)</em> kullanılıyor. Buna göre her kullanıcı sadece kendi Container örnekleri ile çalışıyor. Root kullanıcı yetkisi gerekmemesinin başka bir avantajı daha olabilir. Container başka bir kullanıcı tarafında ele geçirilse bile Root kullanıcı yetkilerine sahip olmadığından sadece o workspace üzerindeki yetkilerle sınırlı kalacaktır.</p>
<p>Podman, Image oluşturmak için Buildah ve uzak repolara image kaydetmek<em>(Register)</em> için skopeo gibi araçları kullanır. Diğer yandan öğrendiğim kadarıyla sadece Linux sistemlerde çalışıyor<em>(Windows Subsystem for Linux bir istisna olabilir mi bakmak lazım)</em> Bununla birlikte Docker Compose'un Podman tarafında henüz bir karşılığı yok<em>(Yazıyı hazırladığım tarih itibariyle doğrulanmamış bir bilgidir. Lütfen araştırınız) </em>Haydi gelin bu Podman nasıl kurulur, temel terminal komutları nelerdir ve onunla bir Poderize işlemi nasıl gerçekleştirilir bir bakalım.</p>
<h2>Önce Kurulum</h2>
<p>Bu seneki pek çok SkyNet çalışmasında olduğu gibi ben denemelerimi Heimdall<em>(Ubuntu-20.04)</em> üzerinde yapmaktayım. Ancak diğer platformlar içinde aynı terminal komutları ve prensipler söz konusu olacaktır. Linux tarafı için şağıdaki şekilde konuya giriş yapabiliriz<em>(Güncel kurulum bilgilerine <a href="https://podman.io/getting-started/installation" target="_blank">resmi adresinden</a> bakılabilir)</em></p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false"># Podman resmi dokümantasyonundaki adımları takip ederek kurulumu yaptım
. /etc/os-release
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -
sudo apt-get update
sudo apt-get -y upgrade
sudo apt-get -y install podman
# Sonrasında bir versiyon kontrolü de yaptım
podman -v</pre>
<p>Kurulum sonrasında birkaç komutla Podman'i inceleyebiliriz. İlgi çekici kısım bir pod oluşturmak ve bu pod içerisine n sayıda container yerleştirmek olacak tabii ki ama önce temeller.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false"># Önce bir pod oluşturalım (adı pod_race olsun)
podman pod create --name pod_race
# Şimdi sistemdeki pod listesine bakalım
podman pod list
# Bu pod içinde bir tane alpine imajından container başlatalım
podman run -d --pod pod_race alpine
# Hadi bir tane de nginx imajından http server container'ı çalıştıralım (aynı pod içinde)
podman run -d --pod pod_race nginx
# Hatta bir tane de rabbitmq container'ı başlatalım. O da aynı pod içinde olsun.
podman run -d --pod pod_race rabbitmq
# Şimdi pod_race isimli pod'un içindeki container'lara bakabiliriz
podman ps -a --pod
# Aşağıdaki komutla yüklü olan image örneklerini de görebiliriz
podman images
# Bir podu aşağıdaki komutla durdurabiliriz. Bu, içindeki Container'ları da durduracaktır.
podman pod stop pod_race
# Pek tabi oluşturulan bir podu, içindeki tüm container örnekleri ile birlikte silebiliriz de
podman pod rm pod_race</pre>
<p>Yukarıdaki temel çalışmaların kısa bir özeti aşağıdaki ekran çıktısındaki gibidir.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/40/Screenshot_01.png" alt="" /></p>
<p>Podman ile uzak depolardaki imajları kolayca arayabiliriz de. Mesela sevgili MariaDB imajlarını aradığımızı ve 20 yıldız üstünde olup automated özellikli olanları bulmak istediğimizi düşünelim...</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">podman search mariadb --filter=stars=20 --filter=is-automated
# ya da resmi bir imaj arayıp açıklamaların da tamamını(--no-trunc) istersek şunu kullanabiliriz
podman search mariadb --no-trunc --filter=is-official
# Hatta çıktı tablosundaki kolonlardan sadece istediklerimizi de mustache stilindeki parametrelerle değiştirebiliriz
podman search --format "table {{.Name}} {{.Stars}}" mariadb --filter=stars=20
# Uzak repolardaki kendi imajlarımızı da aratmak isteyebiliriz.
# Mesela Quay.io'da ki imajlarımızı aratmak istediğimizi düşünelim.
# Aşağıdaki komutla bunu yapabiliriz?
# Lakin kuvvetle muhtemel öncesinde Quay.io için Login olmamız gerekebilir. Podman bunu da sağlar.
podman login quay.io
podman search quay.io/</pre>
<p>Uzak diyarlardaki imajları terminalden nasıl arayacağımızı gördük. Bazen belli bir imajın özelliklerini onu sisteme indirmeden detayda da öğrenmek isteyebiliriz. Bunun için Skopeo aracından yararlanıyoruz. Örneğin alpine imajının son sürümü ile ilgili bir takım temel özellikleri şu komutla öğrenebiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">skopeo inspect docker://docker.io/alpine:latest</pre>
<p>Yukarıdaki terminal komutlarına ait Heimdall çıktıları ise aşağıdaki gibi oluşmuştur.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/40/Screenshot_02.png" alt="" /></p>
<blockquote>
<p>Podman varsayılan kurulumunda image registery adresleri olarak docker ve quay geldi. Başka adresler eklemek istersek<em>(mesela private repo'lar)</em> /etc/containers/registries.conf dosyasını düzenlemek gerekir.</p>
</blockquote>
<p>Şimdi podman ile bir imaj hazırlayıp onu build etmeyi deneyelim. Tahmin edileceği üzere bize kobay bir uygulama lazım ve bunun en basit yolu aptal bir NodeJs servisi. Express web çatısını kullanan bu servisi aşağıdaki terminal komutları ile hazırlayıp kodlayarak devam edelim.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">mkdir pingapi
cd pingapi
npm init -y
touch index.js
npm i express
touch Dockerfile</pre>
<p>index.js içeriğini aşağıdaki gibi yazabiliriz. Sadece masa tenisinin güzel bir spor olduğunu ve bazen her şeye ara verip biraz masa tenisi oynamanın iyi olacağını söyleyeyen bir servis ;)</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">const express = require('express')
const app = express()
app.get('/ping', function (request, result) {
result.send('Biraz ara verip Ping Pong oynayalım mı?')
})
app.listen(5555, "0.0.0.0", function () {
console.log('Servisimiz http://localhost:5555/ping adresinden denenebilir.')
})</pre>
<p>Tabii inşanın olmazsa olmazı Dockerfile dosyamız. Node11 sürümünü baz alarak uygulamamızı olduğu gibi kopyalayıp 5555 nolu port üstünden açacak bir çalışma zamanı ortamını tanımlıyor.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">FROM node:11
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5555
CMD ["node", "index.js"]</pre>
<p>Kobay servisimiz Dockerize<em>(Poderize)</em> edilmeye hazır ;) İzleyen terminal komutları ile onu inşa edelim, sorasında çalıştırıp kullanmayı deneyelim.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false"># Önce Build işlemini yapalım
podman build -t ping-api .
# İmajın oluşup oluşmadığı kontrol ettikten sonra onu
# çalıştırıp api'den değer alıp alamadığımıza bakmak iyi olabilir ;)
podman images
podman run -p 5555:5555 ping-api
podman ps -a
curl http://localhost:5555/ping
# Çalışmakta olan container'ı durdurmak içinse aşağıdaki komutu kullanabiliriz
# (337f id değeri tabii ki siz denerken farklı olacaktır)
podman stop 337f</pre>
<p>İşte çalışma zamanı çıktısı. Podman ile Container ayağa kalktıktan sonra servisi masa tenisi oynamaya götürebiliriz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/40/Screenshot_03.png" alt="" /></p>
<p>Tabii stop komutu ile ilgili container durdurulduğunda servise gönderilen talepler cevapsız kalır. Bu bir nevi Container tatile çıktığında servisin çalışmaması gerektiğinin de bir ispatıdır.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2020/skynet/40/Screenshot_04.png" alt="" /></p>
<h2>Skopeo</h2>
<p>Podman ile ilgili bilgileri araştırırken yanında yardımcı başka araçlar da görebiliriz. OCI ilkelerine göre imaj oluşturmayı kolaylaştıran <a href="https://buildah.io/" target="_blank">Buildah</a><em>(Kanımca Build Yeaaa diye telafuz ediliyor)</em> veya yukarıda bir image nesnesinin detay özelliklerini öğrenmek ve aynı zamanda depolar arası container transferlerini<em>(kendi deponuzla docker.io veya quay.io gibi public registery noktaları arasında taşımak)</em> kolaylaştıran <a href="https://github.com/containers/skopeo" target="_blank">skopeo</a> gibi. Skopeo için Linux tarafında aşağıdaki adımları takip ederek kurulum yapabilirsiniz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">. /etc/os-release
sudo sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x${NAME}_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/x${NAME}_${VERSION_ID}/Release.key | sudo apt-key add -
sudo apt-get -y update
sudo apt-get -y install skopeo</pre>
<p>Şimdilik bu kadar. Gelelim bu çalışma haricinde daha neler yapabileceğinize. Örneğin pod_a ve pod_b şeklinde iki ayrı pod oluşturup içlerindeki container'ların birbirlerini kullanmasını deneyebilirsiniz. Yani pod_a'da ki bir .net web api, pod_b'deki MongoDb container'ını kullanmaya çalışabilir mi sorusunun cevabını arayabilirsiniz. Diğer yandan Podman benzeri OCI standartlarına uyan başka container teknolojileri var mı araştırmakta ve hatta aralarındaki kıyaslamalara bakmakta yarar var. </p>
<p>Böylece geldik bir SkyNet derlememizin daha sonuna. Bu çalışmamızda kobay bir NodeJs servisini Poderize<em>(Dockerize yerine bunu kullanayım dedim)</em> etmeyi ve Podman'in genel kullanımını öğrendik. Örnek kodlara <a href="https://github.com/buraksenyurt/skynet/tree/master/No%2040%20-%20This%20is%20Podman" target="_blank">github reposu</a> üzerinden erişebilirsiniz. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2020-12-27T09:14:00+00:00dockerpodmancontainerOpen Container InitiativekubernetesquayredHatskopeoPoderizeDeamonbsenyurtHeimdall üstünden birşeyler kurcalamak istediğimde yolum genellikle bir Docker imajı ile kesişiyor. Bakmak istediğim bir NoSQL veritabanı mı var, ELK üçlüsü mü gerekli, bir NGinx server ortamımı lazım ya da yeni bir servis için çalışma zamanımı hazırlamam gerekiyor... Hemen Docker kardeşimizin kapısını çalıyorum. Aslında bakarsanız Container teknolojileri denince çoğumuzun aklına Docker'dan başka bir şey gelmiyordur belki de. "Gerçekten de böyle mi?" diye düşündüğüm bir ara Docker'ın güçlü bir alternatifi olan Podman isimli ürünle karşılaştım ve onu biraz tanımaya karar verdim...https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=c777f1d9-2fee-4c58-856e-9345f60ff2e23https://buraksenyurt.com/trackback.axd?id=c777f1d9-2fee-4c58-856e-9345f60ff2e2https://buraksenyurt.com/post/docker-yerine-podman-pod-manager-kullanmak#commenthttps://buraksenyurt.com/syndication.axd?post=c777f1d9-2fee-4c58-856e-9345f60ff2e2https://buraksenyurt.com/post/Peki-ya-Kong-KimPeki ya Kong Kim?2019-05-06T07:00:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/kingkong.jpg" alt="" />Kurumsal mimari ekibinin önerdiği çatılardan birisi üzerine kurulmuş yeni ürünümüzü test ortamına almaya çalıştığımız bir gündü. Local makinelerimizde çok az sorunla ayağa kaldırdığımız proje, test ortamında ne yazık ki daha fazla problem üretmişti. Ağırlıklı olarak web önyüzünden iş kurallarının yürütüldüğü Web API servislerine gidişlerde sorunlar yaşıyorduk.</p>
<p>CI/CD hattındaki parametreleri, veri tabanı nesnelerini, SSO ayarlarını kontrol edip Kibana loglarını incelemeye başladık. Tüm bu işler devam ederken DevOps ekibinden bize destek veren sevigili Yavuz, servisler üzerindeki trafiği monitör etmekteydi. Konuşmalarımız sırasında Docker Container'larının önünde yer alan KONG isimli bir arabirimden bahsetti. O an içimde bir merak uyanmış olsa da aslında sorunların bir an önce çözülmesini istiyordum. Bu yüzden merakımı birkaç hafta sonrasına bıraktım.</p>
<p>Derken artık cumartesi geceleri dışına da taşan <a href="https://github.com/buraksenyurt/saturday-night-works" target="_blank">saturday-night-works</a> çalışmalarımda ona yer verme fırsatı yakaladım. <a href="https://konghq.com/kong/" target="_blank">Kimdi bu Kong?</a> Müzik grubu olan Kong'muydu yoksa Skull adasındaki iri olan mıydı? Belki de API Gateway'di. Onu Westworld üzerinde çalıştırabilir miydim? Öğrenmin yolu basitti. Sonunda macera başladı. Github çalışmaları tamamlandıktan uzun süre sonra da bloğuma not olarak düşmeye karar verdim.</p>
<p>Hali hazırda çalışmakta olduğum firmada, microservice'lerin orkestrasyonu için KONG kullanılıyor. Kabaca bir API Gateway rolünü üstlenen KONG mikro servislere gelen taleplerle ilgili olarak Load Balancing, Authentication, Rate Limiting, Caching, Logging gibi cross-cutting olarak tabir edebileceğimiz yapıları hazır olarak sunuyor<em>(muş)</em> Web, Mobil ve IoT gibi uygulamalar geliştirirken back-end servisleri çoğunlukla mikro servis formunda yaşamaktalar. Bunların orkestrasyonunda görev alan KONG, Lua dili ile geliştirilmiş, performansı ile ön plana çıkan NGINX üzerinde koşan açık kaynaklı bir proje olmasıyla da dikkat çekiyor.</p>
<p>Benim amacım ilk etapta KONG'u WestWorld<em>(Ubuntu 18.04, 64bit)</em> üzerine kurmak ve en az bir servis geliştirip ona gelen talepleri KONG üzerinden geçirmeye çalışmak<em>(Kabaca proxy rolünü üstlenecek diyebiliriz)</em> Normal şartlarda KONG'u sisteme tüm gereksinimleri ile kurabiliriz ancak denemeler için docker imajlarını kullanmak da yeterli olacaktır ki ben bu yolu tercih ediyorum.</p>
<h2>Kobay REST servisleri</h2>
<p>Çalışmada en azından bir Web API servisinin olması lazım. Bir tane .net core bir tane de node.js tabanlı servis geliştirmeye karar verdim. Projeler için WestWorld'de uyguladığım terminal komutları şöyle.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">mkdir services
cd services
dotnet new webapi -o FabrikamApi
touch Dockerfile
touch .dockerignore
mkdir GameCenterApi
cd GameCenterApi
npm init
sudo npm i --save express body-parser
touch index.js
touch Dockerfile</pre>
<p>.Net Core ile geliştirilmiş FabrikamApi servisindeki hazır kod dosyalarında bir kaç değişiklik yapıp, Node.js tabanlı GameCenterApi klasöründeki index.js'i sıfırdan geliştirmem gerekti <em>(Servislerin normal kullanım örneklerine ait <a href="https://github.com/buraksenyurt/saturday-night-works/blob/master/No%2033%20-%20Who%20is%20Kong/assets/postman_samples.json" target="_blank">Postman dosyasını burada</a> bulabilirsiniz)</em> </p>
<p>PlayerController içeriği;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using FabrikamApi.Models;
namespace FabrikamApi.Controllers
{
/*
PlayersController isimli Controller sınıfı Player türünden bir listeyle çalışıyor.
Konumuz KONG'u tanımak olduğu için çok detalı bir servis değil.
Temel Get, Post, Put ve Delete operasyonlarını içermekte.
Listeyi static bir değişkende tutuyoruz. Dolayısıyla servis sonlandırıldığında bilgiler uçacaktır.
Ancak isterseniz kalıcı bir repository ekleyebilirsiniz.
*/
[Route("api/v1/[controller]")]
[ApiController]
public class PlayersController : ControllerBase
{
private static List<Player> playerList = new List<Player>{
new Player{Id=1000,Nickname="Hatuta Matata",Level=100}
};
[HttpGet]
public ActionResult<IEnumerable<Player>> Get()
{
return playerList;
}
[HttpGet("{id}")]
public ActionResult<Player> Get(int id)
{
var p = playerList.Where(item => item.Id == id).FirstOrDefault();
if (p != null)
{
return p;
}
else
{
return NotFound();
}
}
[HttpPost]
public void Post([FromBody] Player player)
{
playerList.Add(player);
}
[HttpPut("{id}")]
public IActionResult Put(int id, [FromBody] Player player)
{
var p = playerList.Where(item => item.Id == id).FirstOrDefault();
if (p != null)
{
p.Nickname = player.Nickname;
p.Level = player.Level;
return Ok();
}
else
{
return NotFound();
}
}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var p = playerList.Where(item => item.Id == id).FirstOrDefault();
if (p != null)
{
playerList.Remove(p);
return Ok();
}
else
{
return NotFound();
}
}
}
}</pre>
<p>PlayerController tarafından kullanılan Player sınıfı içeriği;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace FabrikamApi.Models
{
public class Player{
public int Id { get; set; }
public string Nickname { get; set; }
public int Level { get; set; }
}
}</pre>
<p>FabrikamAPI ye ait Docker ve .dockerignore içerikleri;</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">FROM microsoft/dotnet:sdk AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM microsoft/dotnet:aspnetcore-runtime
WORKDIR /app
COPY --from=build-env /app/out .
ENV ASPNETCORE_URLS=http://+:65001
ENTRYPOINT ["dotnet", "FabrikamApi.dll"]</pre>
<p>Başlangıçta dotnet:sdk imajından yararlanılacağı bildiriliyor. Çalışma klasörü bildirildikten sonra proje dosyasının kopyalanıp paketlerin yüklenmesi için restore işlemi başlatılıyor. Diğer her şeyin kopylanamasını bir build işlemi takip ediyor ki burada release versiyonu da çıkılıyor. Çalışma zamanı imajı alındıktan sonra 65001 numaralı port yayın noktası olarak belirtiliyor. Son adımsa dll'i çalıştıran dotnet komutunu içermekte. Birde bin ve obj klasörlerinin docker ortamında yer almaması için .dockerignore isimli dosyamız var. İçeriği oldukça basit.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">bin\
obj\</pre>
<p>games isimli json veri dizisi ile ilgili basit get operasyonları içeren GameCenterApi uygulamasındaki kod içeriklerimiz ise şöyle.</p>
<p>index.js</p>
<pre class="brush:js;auto-links:false;toolbar:false" contenteditable="false">/*
GameCenterApi'den yayına alınan bu dummy servis games isimli diziyi döndüren iki basit fonksiyonelliğe sahip.
*/
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const games = [
{
id: 1,
title: 'Red Dragons',
maxPlayerCount: 10
},
{
id: 2,
title: 'Green Barrets',
maxPlayerCount: 24
},
{
id: 3,
title: 'River Raid',
maxPlayerCount: 4
},
{
id: 4,
title: 'A-Team',
maxPlayerCount: 9
},
];
app.use(bodyParser.json());
app.get('/api/v1/games', (req, res) => {
res.json(games);
});
app.get('/api/v1/games/:id', (req, res) => {
res.json(games[req.params.id]);
});
app.listen(65002, () => {
console.log(`Oyun servisi aktif! http://localhost:65002/api/v1/games`);
});</pre>
<p>DockerFile dosyası</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">FROM node:carbon
# create work directory
WORKDIR /usr/src/app
# copy package.json
COPY package.json ./
RUN npm install
# copy source code
COPY . .
EXPOSE 65002
CMD ["npm", "start"]</pre>
<p>Dosya node.js ortamlarından birisini ifade eden carbon bildirimi ile başlıyor. İmaj buradan alınacak. Çalışma klasörünün oluşturulması, package.json dosyasının burayı alınıp proje bağımlılıklarının install edilmesi, uygulamanın 65002 numaralı porttan ayağa kaldırılması diğer bildirimler olarak karşımıza çıkıyor.</p>
<p>Geliştirme noktasında servislerin çalıştığını kontrol etmemiz gerekiyor. FabrikamAPI isimli .Net Core tabanlı servisi çalıştırmak için,</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">dotnet run</pre>
<p>terminal komutunu verip http://localhost:65001/api/v1/players adresine gidebiliriz. GameCenterApi isimli Node.js tabanlı servisi çalıştırmak içinse package.json içerisine aldığımız start kod adlı script'i işlettirebiliriz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">npm run start</pre>
<p>Sonrasında http://localhost:65002/api/v1/games adresi üzerinden bu servisi de test edebiliriz.</p>
<blockquote>
<p>localhost bilgisi ilerleyen kısımlarda görüleceği gibi Docker'a geçildikten sonra değişmektedir.</p>
</blockquote>
<h2>Servislerin Dockerize Edilmesi</h2>
<p>Dikkat edilmesi gereken noktalardan birisi de, her iki örneğin Dockerize edilebilecek şekilde Dockerfile dosyaları ile donatılmış olmalarıdır. İlaveten .Net Core uygulamasında .dockerignore dosyası vardır. Bunu build context'ini ufalamak için kullanıyoruz. Docker imajları KONG tarafından kullanılacakları için önemli. </p>
<p>FabrikamApi uygulaması için Dockerize işlemleri aşağıdaki terminal komutuyla yapılabilir.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker build -t fma_docker .</pre>
<p>GameCenterApi isimli Node.js uygulaması içinse aşağıdaki gibi.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker build -t gca_docker .</pre>
<p>Dockerize işlemleri tamamlandıktan sonra container'ları çalıştırıp kontrol etmemizde yarar var. İlk iki komutla ayağa kaldırıp son komutla listede olup olmadıklarına bakıyoruz.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker run -d --name=game_center_api gca_docker
docker run -d --name=fabrikam_api fma_docker
docker ps -a</pre>
<p>WestWord'de durum aşağıdaki gibi.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_1.png" alt="" /></p>
<blockquote>
<p>Docker imajları çalışmaya başladıktan sonra servislere hangi IP adresi üzerinden gitmemiz gerektiğine bakmak için 'docker inspect game_center_api' ve 'docker inspect fabrikam_api' komutlarından yararlanabiliriz. Bize uzun bir Json içeriği dönecektir ancak son kısımda IPAddress bilgisini yakalayabiliriz. WestWorld için docker tabanlı adresler http://172.17.0.3:65001/api/v1/players ve http://172.17.0.2:65002/api/v1/games şeklinde oluştu. Sizin sisteminizde bu IP adresleri farklı olabilir.</p>
</blockquote>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_2.png" alt="" /></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_3.png" alt="" /></p>
<h2>Kong Kurulumları ve Docker Servislerinin Dahil Edilmesi</h2>
<p>Tüm işlemleri Docker Container'lar üzerinde yapacağız. Bu nedenle kendimize yeni bir ağ oluşturarak işe başlamakta yarar var. Aşağıdaki terminal komutları ile devam edelim.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker network create sphere-net
docker run -d --name kong-db --network=sphere-net -p 5555:5432 -e "POSTGRES_USER=kong" -e "POSTGRES_DB=kong" postgres:9.6
docker run --rm --network=sphere-net -e "KONG_DATABAE=postgres" -e "KONG_PG_HOST=kong-db" kong:latest kong migrations bootstrap
docker run -d --name kong --network=sphere-net -e "KONG_LOG_LEVEL=debug" -e "KONG_DATABASE=postgres" -e "KONG_PG_HOST=kong-db" -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" -e "KONG_PROXY_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" -p 9000:8000 -p 9443:8443 -p 9001:8001 -p 9444:8444 kong:latest</pre>
<ul>
<li>İlk komutla sphere-net isimli bir docker network'ü oluşturuyoruz.</li>
<li>İkinci uzun komutla Postgres veri tabanı için bir Container başlatıyoruz. sphere-net ağında çalışacak olan veri tabanını KONG kullanacak. KONG, veri tabanı olarak Postgres veya Cassandra sistemlerini destekliyor. Eğer yerel makinede Postgres imajı yoksa <em>(ki örneği denediğim dönemde WestWorld'de yoktu)</em> pull işlemi biraz zaman alabilir.</li>
<li>Üçüncü komutla Postgres veri tabanının KONG için hazırlanması söz konusu.</li>
<li>Dördüncü ve uzuuuuuun bir parametre listesine sahip komutla da KONG Container'ını çalıştırıyoruz <em>(üşenmedim, kopyalamadan yazdım. Siz de öyle yapın)</em></li>
</ul>
<p>Bu adımlardan sonra kong ve postgres ile ilgili Container'ların çalıştığını teyit etmeliyiz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_4.png" alt="" /></p>
<p>Hatta http://localhost:9001 adresine bir HTTP GET talebi attığımızda konfigurasyon ayarlarını da görebiliriz. 9001 portu <em>(Normal kurulumda 8001 de olabilir)</em> yönetsel işlemlerin bulunduğu servis katmanıdır. Service ekleme, silme, görüntüleme ve güncelleme gibi işlemler 9001 portundan ulaşılan servisçe yapılır <em>(Route yönetimi içinde aynı şey söz konusudur)</em></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_5.png" alt="" /></p>
<p>Komutlar biter mi? Şimdi servislere ait Container'ları sphere-net üzerinde çalışacak şekilde ayağa kaldırmalıyız.</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker run -d --name=game_center_api --network=sphere-net gca_docker
docker run -d --name=fabrikam_api --network=sphere-net fma_docker
docker ps -a</pre>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_6.png" alt="" /></p>
<blockquote>
<p>KONG için bir Docker Network oluşturduk. Bu ağa dahil olan ne kadar Container varsa IP adresleri farklılık gösterecektir. sphere-net'e dahil olan Container'ların host edildiği IP adreslerini öğrenmek için terminalden 'docker inspect sphere-net' komutunu çalıştırabiliriz.</p>
</blockquote>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_7.png" alt="" /></p>
<h2>Çalışma Zamanı <em>(Bir başka deyişle KONG üzerinde servislerin ayarlanması)</em></h2>
<p>KONG, veri tabanı olarak kullanılan Postgres ve geliştirdiğimiz iki REST Servisine ait Docker Container'ları ayakta. WestWorld'deki güncel duruma göre</p>
<ul>
<li>http://172.19.0.4:65002/api/v1/games adresinde Node.js tabanlı servisimiz yaşıyor.</li>
<li>http://172.19.0.5:65001/api/v1/players adresinde ise .Net Core Web API servisimiz bulunuyor.</li>
</ul>
<p>Amacımız şu anda localhost:9000 adresli KONG servisine gelecek olan games ve players odaklı talepleri aslı servislere iletmek. Yani KONG ilk etapta bir Proxy servis şeklinde davranış gösterecek. Bunun için öncelikle servislerimizi KONG'a eklemeliyiz. KONG'a eklenen servisler http://localhost:9001/services adresinden izlenebilir ve hatta yönetilebilirler. Şimdi bu adrese aşağıdaki içeriğe sahip POST komutunu gönderelim <em>(Postman ile yapabilir veya curl komutu ile terminalden icra edebiliriz)</em></p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">URL : http://localhost:9001/services
Method : HTTP Post
Content-Type : application/json
Body :
{
"name":"api-v1-games",
"url":"http://172.19.0.4:65002/api/v1/games"
}</pre>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_8.png" alt="" /></p>
<p>Bu işlemi FabrikamAPI içinde yaptıktan sonra http://localhost:9001/services adresine gidersek servis bilgilerini görebiliriz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_9.png" alt="" /></p>
<p>Servisleri eklemek yeterli değil. Route tanımlamalarını da yapmak gerekiyor <em>(KONG tarafındaki entrypoint tanımlamaları için gerekli bir aksiyon olarak düşünebiliriz)</em> KONG services'e aşağıdaki içeriğe sahip talepleri göndererek gerekli route tanımlamaları yapılabilir.</p>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">URL: http://localhost:9001/services/api-v1-players/routes
Method : HTTP Post
Content-Type : application/json
Body :
{
"hosts":["api.ct.id"],
"paths":["/api/v1/players"]
}</pre>
<pre class="brush:plain;auto-links:false;toolbar:false" contenteditable="false">URL: http://localhost:9001/services/api-v1-games/routes
Method : HTTP Post
Content-Type : application/json
Body :
{
"hosts":["api.ct.id"],
"paths":["/api/v1/games"]
}</pre>
<p>Oluşan route bilgilerini http://localhost:9001/routes adresinden görebiliriz. Her iki servis için gerekli route tanımlamaları başarılı bir şekilde yapıldıktan sonra KONG üzerinden GameCenterAPI ve FabrikamAPI servislerine erişebiliyor olmamız gerekir.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2019/04/33/credit_10.png" alt="" /></p>
<h2>Yararlandığım Diğer Docker Komutları</h2>
<p>Örneği geliştirirken yararlandığım bazı Docker komutları da oldu. Mesela çalışan Container'ları stop komutu sonrası durduramayınca,</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">sudo killall docker-containerd-shim</pre>
<p>Container'larımı görmek için,</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker ps -a</pre>
<p>Container'ları sık sık remove etmem gerektiğinden,</p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker rm {ContainerID}</pre>
<p>Container'ın tüm bilgilerini görmem gerektiğinde de<em>(özellikle IP adresini)</em></p>
<pre class="brush:bash;auto-links:false;toolbar:false" contenteditable="false">docker inspect {container adı}
docker inspect {ağ adı}</pre>
<h2>Ben Neler Öğrendim</h2>
<p>Doğruyu söylemek gerekirse <a href="https://github.com/buraksenyurt/saturday-night-works" target="_blank">Saturday-Night-Works</a> çalışmalarının herbirisi bana tahmin ettiğimden de çok şey öğretiyor. 33 numaralı örnekten yanıma kar olarak kalanları şöyle sıralayabilirim.</p>
<ul>
<li>KONG'un temel olarak ne işe yaradığını</li>
<li>.Net Core ve Node.js tabanlı servis uygulamaları için Dockerfile dosyalarının nasıl hazırlanacağını</li>
<li>KONG a bir servis ve route bilgisinin nasıl eklenebileceğini</li>
<li>Bolca Docker terminal komutunu</li>
<li>Docker Container içine açılan uygulamaların asıl IP adreslerini nasıl görebileceğimi</li>
</ul>
<p>Bu macerada API Gateway olarak kullanılabilen KONG isimli ürünü bir Linux platformunda docker imajları üzerinde deneyimlemeye çalıştık. Böylece geldik bir maceramızın daha sonuna. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2019-05-06T07:00:00+00:00kongapi gatewaymicroserviceweb apinodenode.jsjavascriptc#dockercontainerdockerizedockerfilepostgresapibsenyurtHali hazırda çalışmakta olduğum firmada, microservice'lerin orkestrasyonu için KONG isimli bir araç kullanılıyor. Kabaca bir API Gateway rolünü üstlenen KONG microservice'lere gelen request'lerle ilgili olarak Load Balancing, Authentication, Rate Limiting, Caching, Logging gibi cross-cutting olarak tabir edebileceğimiz yapıları hazır olarak sunuyor(muş) Web, Mobil ve IoT gibi uygulamalar geliştirirken backend servisleri çoğunlukla microservis formunda yaşamaktalar. Bunların orkestrasyonunda görev alan KONG, Lua dili ile geliştirilmiş performansı ile ön plana çıkan NGINX üzerinde koşan açık kaynaklı bir proje olmasıyla da dikkat çekiyor.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=01e728de-4498-4d6c-8cb0-1186ffa481e42https://buraksenyurt.com/trackback.axd?id=01e728de-4498-4d6c-8cb0-1186ffa481e4https://buraksenyurt.com/post/Peki-ya-Kong-Kim#commenthttps://buraksenyurt.com/syndication.axd?post=01e728de-4498-4d6c-8cb0-1186ffa481e4https://buraksenyurt.com/post/teknik-borclari-azaltmakTeknik Borçları(Technical Debt) Azaltmak2019-01-04T05:03:00+00:00bsenyurt<p><img style="float: right;" src="https://buraksenyurt.com/image.axd?picture=/2018/09/sonar_7.gif" alt="" />Merhaba Arkadaşlar,</p>
<p class="graf graf--p">Bir yazılım ürünü geliştirilirken dikkat edilmesi gereken konuların başında kod kalitesi geliyor. Kaliteli kod, bilinen kodlama standartlarına uyan, okunabilirliği yüksek, karmaşıklığı az, dokümante edilmiş ve bakımı yapılabilir özellikleri barındırmak durumunda. Bu kurallara uymaya çalışmak geliştirme sürelerini uzatsa da uzun vadede kalitenin korunması için gerekli. Üstelik endüstüriyel normlara uygun, derecelendirilebilir uygulamalar geliştirmek istiyorsak kuvvetle üzerinde durulması gereken bir konu. Eğer kaliteyi bozacak ihlaller yaparsak uygulama arkasında ödenmesi zor büyük borçlar bırakabiliriz. Nam-ı diğer Teknik Borç<em class="markup--em markup--p-em">(Technical Debt)</em></p>
<p class="graf graf--p">Teknik borç yeni bir kavram değil. İlk olarak Wiki’nin kurucusu, Extreme Programming ve Design Patterns kavramlarının öncülerinden olan Ward Cunningham tarafından ortaya konulmuştur. Oluşmasına etken olan sebepler vardır. Bazen geliştirilen ürünün proje bitiş süresi sebebiyle mecburen stratejik olarak kabul edilir ya da ekip kendi insiyatifinde bunu taktiksel olarak kabul edebilir. Bazı durumlarda ekibin yetkinliğinin az olması sebebiyle ortaya çıkar. Ancak belki de en kötüsü teknik borç üstüne yeni yapılan geliştirmelerin getirdiği ek borçlardır.</p>
<blockquote class="graf graf--pullquote">Bazen artık vazgeçilmesi gereken teknikler üzerine oturmuş çözümlerin, Tool güncelemeleri ile revize edilerek yaşatılması yoluna gidilir. Bu, stratejik bir karar olmakla birlikte kök nedeni gidermekten uzak bir yaklaşımdır.</blockquote>
<p class="graf graf--p">Teknik borçların bir kısmı pek çoğumuzun bilmeden de olsa gelecek programcılara bıraktığı ve hatta istemeden de olsa üzerine aldığı sorunlardır aslında. Bu sorunlar sebebiyle zamanla kalitesi bozulan, problemleri çoğalan, güvenilirliği ve daha da kötüsü itibarı azalan ürünler ortaya çıkar. Teknik borçların temizlenmesi mi, müşterinin yeni isteklerinin karşılanması mı derken ürün, üzerinde çalışan programcıları eskitmeye de devam eder. <span class="markup--quote markup--p-quote is-other" data-creator-ids="163eb811a0ab">Sonunda legacy olarak tanımlanan, işini yapan ama kimsenin de ellemek istemediği yaşamını devam ettiren korkutucu projeler oluşur.</span></p>
<blockquote class="graf graf--pullquote">Uygulama çalışır halde olduğu ve müşteri istekleri karşılandığı sürece ürünün başarılı olduğu düşünülür. Ancak teknik borçlanma arttıkça oluşan bakım maliyetleri ve ek olarak gelen başka sorunlar bir noktadan sonra can sıkıcı hal almaya başlar.<br /><br />Yeni istekler için hesapta olmayan başka bulguları da ortadan kaldırmaya çalışırken uygulanan hızlı çözümler borç üstüne borç ekler. Nihayetinde müşteri(herkes diyebiliriz) bence mutsuz olur.<br /><br />Unutulmamalıdır ki motivasyon kaybı, çözüm üretmenin önündeki en büyük engellerdendir.</blockquote>
<p id="4a07" class="graf graf--p graf-after--pullquote">Teknik borçlanmanın önüne geçmek için alınabilecek belli başlı tedbirler var. Her şeyden önce yazılım geliştirme şeklimizi değiştirmemiz gerekiyor. <span class="markup--quote markup--p-quote is-other" data-creator-ids="163eb811a0ab">DevOps gibi kültürlerde yaşamalı, şeffaf olmalı, çevik teknikleri işin içerisine katmalı, pair programming uygulamaktan korkmamalıyız.</span></p>
<p id="9797" class="graf graf--p graf-after--p">Test odaklı geliştirme de kalitenin artması için önemli. Hatta DevOps’un olmazsa olmazlarından birisi. TDD<em class="markup--em markup--p-em">(Test Driven Development)</em> en azından Red, Green, Blue ilkesine göre kod geliştirmemizi öneriyor. Blue<em class="markup--em markup--p-em">(Refactoring)</em>olarak nitelendirilen ve kodun yeniden gözden geçirildiği kısım bile sonradan oluşacak borçların önüne geçmek için önemli. Hatta Code Review süreçlerinin işletilmesi de gerekiyor. Pull Request kavramı da buna hizmet eder nitelikte<em class="markup--em markup--p-em">(Farkındaysanız bunların tamamı DevOps kültüründe bahsi geçen konulardan)</em></p>
<p id="92e9" class="graf graf--p graf-after--p">Aşağıdaki tabloda kodu yeniden gözden geçirmenin ve iyileştirmenin teknik borçlanma ile olan ilişkisi ifade ediliyor. Zaman ilerledikçe refactor edilmeyen kodlar teknik borcun artmasına ve değişim maliyetlerinin yükselmesine neden olmakta. Hayatlarımızın belli dönemlerinde rastladığımız<em class="markup--em markup--p-em">(rastlayacağımız)</em> o büyük projeleri düşünün. Hani bakım maliyetleri yüksek olan. Temel sebep, zaman içerisinde çoğalarak artan teknik borç miktarıdır.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2018/09/sonar_6.gif" alt="" /></p>
<p class="graf graf--p">Yazılımcıya düşen bir çok görev var. Test güdümlü yazılım geliştirmeye yatkın olması, kod kalite standartlarından haberdar olması, kokan koddan rahatasızlık duyması, kodlama standartlarının farkında olması, temiz kodun ne anlama geldiğini bilmesi çok önemli. Ancak birey olarak bilinçlenmek de yeterli değil. Kullandığımız programlama dillerinden ortamlara kadar hemen her şey zamanla yarışırcasına yenileniyor, değişiyor. Dolayısıyla temel bilgileri bilsek bile yardımcı araçlardan faydalanmak gerekiyor.</p>
<blockquote class="graf graf--pullquote">Çeşitli ölçümleme araçları ile elde edeceğimiz metrik değerler bulunuğumuz durumu görmek, iyiye mi gidiyoruz bilmek, çeşitli riskleri erkenden hissedip gerekli tedbirleri önceden alabilmek için her alanda olduğu gibi yazılım kalite örgüsünde de kritik.</blockquote>
<p class="graf graf--p">Örneğin kodun statik ve dinamik olarak analiz edilmesi, raporlar çıkartılması ve buna göre gerekli düzeltmelerin yapılması için belli başlı araçlardan yararlanılabilir. SonarQube da bu araçlardan birisi ve beni teknik borçlanma ile ilgili olarak bildiklerimi özetlememin sebepleri arasında.</p>
<blockquote class="graf graf--pullquote">SonarQube bir statik kod analiz aracıdır. Continuous Inspection<em class="markup--em markup--pullquote-em">(Sürekli denetim)</em> olarak tanımlanan kültürün bir parçası olarak kod kalitesini arttırmak için CI/CD hattında kullanılır.<br /><br />Kodun boyutu, test edilirliliği, karmaşıklığı, tekrarları, güvenlik açıkları gibi kısımlarına odaklanır. Temel amaç teknik borçların azaltılması için gerekli çıktıları sunmak ve önerilerde bulunmaktır.</blockquote>
<p id="f9e7" class="graf graf--p graf-after--pullquote">Biz de DevOps odaklı kültür değişimimiz süresince kod kalitesini arttırmak ve teknik borçları azaltmak için bazı araçlardan yararlanıyor ve hatta danışmanlık alıyoruz<em class="markup--em markup--p-em">(Burada </em><a class="markup--anchor markup--p-anchor" href="https://sahabt.com/" target="_blank" rel="nofollow noopener" data-href="https://sahabt.com/"><em class="markup--em markup--p-em">Saha Bilgi Teknolojileri</em></a><em class="markup--em markup--p-em"> ve </em><a class="markup--user markup--p-user" href="https://medium.com/@emredundar" target="_blank" data-href="https://medium.com/@emredundar" data-anchor-type="2" data-user-id="cf1aed6d40d9" data-action-value="cf1aed6d40d9" data-action="show-user-card" data-action-type="hover"><em class="markup--em markup--p-em">Emre Dundar</em></a><em class="markup--em markup--p-em"> için ayrı bir parantez açmam lazım. Özellikle kod kalitesinin arttırılmasına yönelik farkındalığın oluşturulmasında çok değerli katkıları var)</em></p>
<p id="4b7c" class="graf graf--p graf-after--p">Tabii test odaklı geliştirilmeyen, üzerinden çokça yazılımcının geçtiği yaşlı projelerde bu araçların sonuçları pek de beklediğimiz<em class="markup--em markup--p-em">(aslında beklediğimiz)</em>gibi değil. Yeni nesil ürünlerde ise inanılmaz derecede yardımcı oluyor ve işin başında tedbirler almamızı sağıyor. Nitekim belirli ihlaller ürünün çıkmaması için yeterli.</p>
<p id="4369" class="graf graf--p graf-after--p">Bu amaçla SonarQube ve SonarLint araçlarından yararlanıyoruz. SonarQube, VSTS Continuous Integration hattı üzerinde devreye girmekte. Konulan kurallara bağlı olaraktan check-in’lenmiş kodun Continuous Delivery noktasına geçirilmesine veya geçirilmemesine karar verebiliyor. Eğer sorunlar varsa bunlar için geri bildirimlerde bulunuyor<em class="markup--em markup--p-em">(Bug’ın sahibine mail ile bildirilmesi gibi)</em> Aşağıdaki örnek ekran görüntüsünde aracın var olan ürünlerimizden birisi için olan rapor ekranını görebilirsiniz<em class="markup--em markup--p-em">(Şeffaf olmaktan zarar gelmez)</em></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2018/09/sonar_1.gif" alt="" /></p>
<p class="graf graf--p">Burada çok önemli bilgiler yer alıyor. Örneğin projede toplam 48 bug varmış ve son yapılan geliştirmeler sonrası 13 bug daha dahil olmuş. A, E, D gibi ifadelerle sınav notumuzu görebiliyoruz. Vulnerabilities kısmı kritik. Hatta ilk ele alınan kısım olduğunu ifade edebilirim. Burada özellikle kod bazlı injection’a sebep olabilecek güvenlik açıkları gibi bilgiler yer alıyor. <a class="markup--anchor markup--p-anchor" href="https://www.owasp.org/index.php/Main_Page" target="_blank" rel="nofollow noopener" data-href="https://www.owasp.org/index.php/Main_Page">OWASP</a> benzeri standartlar göz önüne alınarak çalıştırılan kurallar da söz konusu.</p>
<blockquote class="graf graf--pullquote">SonarQube benzeri kod analiz araçlarından birisi de Cast’tir. Ancak Cast dinamik kod analizi yapar. Yani kodu çalışma zamanında denetler ve buna göre rapor üretir. ING Bank bünyesinde çalıştığım dönemlerde Cast aracından yararlanılmaktaydı. Aylık olarak gelen raporlarda temizlenmesi beklenen önceliklendirilmiş bulgu listesi yer alırdı.</blockquote>
<p id="0e96" class="graf graf--p graf-after--pullquote">Bir de tabii <a class="markup--anchor markup--p-anchor" href="http://wiki.c2.com/?CodeSmellMetrics" target="_blank" rel="nofollow noopener" data-href="http://wiki.c2.com/?CodeSmellMetrics">kokan kod<em class="markup--em markup--p-em">(Code Smells)</em></a> durumu vardır. Kod standartlarına pek uyulmadığı durumlarda bir süre sonra kodda unutulan iyileştirmelerin sayısı artar. Bu da teknik borç oluşmasına sebebiyet veren etkenlerdendir. Nitekim kodun okunurluğunu zorlaştıran, boat anchor gibi anti-pattern’lerin oluşmasına neden olan durumlar vardır<em class="markup--em markup--p-em">(Daha fazlası için </em><a class="markup--anchor markup--p-anchor" href="https://medium.com/@burakselyum/y%C4%B1llar-ge%C3%A7sede-de%C4%9Fi%C5%9Fmeyen-%C5%9Feyler-var-121ddf9c0476" target="_blank" data-href="https://medium.com/@burakselyum/y%C4%B1llar-ge%C3%A7sede-de%C4%9Fi%C5%9Fmeyen-%C5%9Feyler-var-121ddf9c0476"><em class="markup--em markup--p-em">sizi şöyle alalım</em></a><em class="markup--em markup--p-em">) </em>Koddan koku geldiğini anlamanın belli semptomları vardır. Bunları kabaca aşağıdaki gibi sıralayabiliriz.</p>
<ul class="postList">
<li id="f10a" class="graf graf--li graf-after--p">Tekrar eden kod parçaları<em class="markup--em markup--li-em">(Duplicated Code)</em></li>
<li id="e0a1" class="graf graf--li graf-after--li">Anlaşılması güç uzun metod gövdeleri</li>
<li id="dd30" class="graf graf--li graf-after--li">Birden çok şeyi yapmaya çalışan büyük sınıflar<em class="markup--em markup--li-em">(God Object)</em></li>
<li id="97d9" class="graf graf--li graf-after--li">Çok sayıda parametre</li>
<li id="8d62" class="graf graf--li graf-after--li">Birden fazla yerde tekrar eden Switch ifadeleri</li>
<li id="c09b" class="graf graf--li graf-after--li">Attığı taş kurbayı ürkütmez felsefesindeki tembel sınıflar <em class="markup--em markup--li-em">(Lazy Class)</em></li>
<li id="c0c5" class="graf graf--li graf-after--li">Kodun ne yaptığını anlatan yorum satırları<em class="markup--em markup--li-em">(Bu kısım her zaman tartışmaya açık sanırım)</em></li>
<li id="5b9a" class="graf graf--li graf-after--li">…</li>
</ul>
<p id="9ec1" class="graf graf--p graf-after--li">Tekrar grafiğe dönecek olursak kokan kodların temizlenmesi için öngörülen sürelerin de yer aldığını görebiliriz. Toplamda 13 günlük<em class="markup--em markup--p-em">(tahmini bir süre ve aracın bunu hangi tip developer’a göre verdiğini henüz anlayamadım)</em> bir çalışma yapılması gerektiği ifade edilmekte. Diğer yandan bu yaşlı uygulama için Code Coverage değeri yüzde sıfır. Yani kodun hiç bir kısmı için test yazılmamış durumda. Bu pek de iyi bir durum değil. Kodun test edilebilir olması çok önemli. Raporun bir kısmında da tekrar eden kod bloklarına yer veriliyor. Bu proje özelinde kodun %1.8lik kısmı kod tekrarı içermekte. 188 kod bloğunun tekrar edildiği ifade ediliyor. Issues kısmına geldiğimizde durumla ilgili olarak daha fazla detay görebiliriz.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2018/09/Sonar_2.gif" alt="" /></p>
<p class="graf graf--p">Severity bölümünde yer alan kısımda derecelerine göre seviyelendirilmiş bulgular yer alıyor. Tahmin edileceği üzere Blocker, Critical ve Major kategorisine giren maddeler öncelikli olarak değerlendirilmeliler. Aşağıda bu kısımlara ait örnekler yer alıyor.</p>
<p>Blocker örneği<em>(1o dakikalık bir efor öngörülüyor ve kokan kod kategorisinde olup bizi bloklayacak bir problemden bahsediliyor)</em></p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2018/09/sonar_3.gif" alt="" /></p>
<p>Critical örneği.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2018/09/sonar_4.gif" alt="" /></p>
<p>Major örneği.</p>
<p><img src="https://buraksenyurt.com/image.axd?picture=/2018/09/sonar_5.gif" alt="" /></p>
<p class="graf graf--p">Bu bulgulara bakıldığında SonarQube’ün detaylı çözüm yollarını ve sorunun olduğu kod dosyalarını görebiliyoruz. Tüm bu kriterlere göre bir Quality Gate puanı hesaplanıyor. Şu anki tabloya göre kodun güvenilirliğinin zayıf olduğunu ve bu sebepten Failed statüsünde kaldığını söyleyebiliriz. Yani CI Server bu paketi hiç bir şekilde taşıma kapısına göndermeyecek.</p>
<p class="graf graf--p"><img src="https://buraksenyurt.com/image.axd?picture=/2018/11/gandalf_2.gif" alt="" /></p>
<blockquote>
<p>SonarQube CI server üzerinde kurgulanan bir ürün ancak <a class="markup--anchor markup--pullquote-anchor" href="https://sonarcloud.io/about" target="_blank" rel="nofollow noopener" data-href="https://sonarcloud.io/about">bulut tabanlı bir sürümü</a> de bulunuyor. Hatta <a class="markup--anchor markup--pullquote-anchor" href="https://hub.docker.com/_/sonarqube/" target="_blank" rel="nofollow noopener" data-href="https://hub.docker.com/_/sonarqube/">Docker imajını</a> kullanmak da mümkün.</p>
</blockquote>
<p class="graf graf--p">Geliştirici olarak SonarQube sunucusuna gelmeden önce de bir takım tedbirler alabiliriz. Bu noktada SonarLint aracından yararlanabileceğimizi ifade edebilirim. SonarQube sunucusu ile de entegre olabildiği için şirket bünyesinde konulan kural setlerine bağlı kalarak geliştirme yapma şansımız var. Ama yoksa bile local geliştirmeler için varsayılan kural setlerinden yararlanmak mümkün. Hem Visual Studio hem de Code ile eklenti olarak kullanılabilen bir ürün SonarLint.</p>
<blockquote class="graf graf--pullquote">Kendi github(veya benzeri) repository’inizdeki deneysel projelerinizde çalışırken bile kod kalite standartlarını uygulatmanızı öneririm. Bu, kaliteli kod üretme alışkanlığını kazanmak için önemli bir pratiktir.</blockquote>
<p id="1b2c" class="graf graf--p graf-after--pullquote">Pek tabii static kod analizi için geliştirme ortamı ile birlikte gelen ürünler de kullanılabilir. SonarQube, CI hattı ile entegre olabilen merkezi bir statik kod analiz aracı olduğu için local araçlara göre daha fazla tercih edilmekte. Aslında muadil olan ürünler de mutlaka var. Çok fazla araç bağımlısı olmamak da gerekiyor belki ama kod kalitesini arttırmak ve teknik borç yükünü azaltmak için farkındalık yaratacak araçlar bulunduğunu söyleyebiliriz. Biz yazılım geliştiricilerin de bu çerçevede düşünmesi gerekiyor. Eğer yeni bir ürün geliştirmeye başlıyorsanız boyutuna göre mutlaka statik kod analizine tabii olun derim.</p>
<p id="9a27" class="graf graf--p graf-after--p graf--trailing">Farkında olalım, farkında kalalım.</p>2019-01-04T05:03:00+00:00test driven developmentcode coveragequality assuranceteknik borçtecnichal deptbugsvulerabilitiesdebtcode smellsdryyagnikissclean codecode metricscontinuos inspectioncontinuous integrationbsenyurtTeknik borçlar pek çoğumuzun bilmeden de olsa gelecek programcılara bıraktığı sorunlar. Bu sorunlar sebebiyle zamanla kalitesi bozulan ürünler ortaya çıkıyor. Teknik borçların temizlenmesi mi, müşterinin yeni isteklerinin karşılanması mı derken ürün üzerinde çalışan programcıları eskitmeye devam edebiliyor. Sonunda legacy olarak tanımlanan, kimsenin ellemek istemediği ama yaşamını devam ettirmek zorunda olan devasa projeler oluşuyor. Bunun önüne geçmek sanıldığı kadar zor değil aslında. En başından test odaklı yaklaşımlarla ilerlemek sadece bir başlangıç.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=9744f6e2-6b25-4695-a926-9179153e40924https://buraksenyurt.com/trackback.axd?id=9744f6e2-6b25-4695-a926-9179153e4092https://buraksenyurt.com/post/teknik-borclari-azaltmak#commenthttps://buraksenyurt.com/syndication.axd?post=9744f6e2-6b25-4695-a926-9179153e4092