Kariyer.Net’te DevOps Platform Dönüşüm ve Modernizasyon Süreci — 2-Altyapı Kurulum Otomasyonu &…
Merhabalar, önceki yazımızda genel olarak mevcut yapıyı analiz etmiş yapılacakları planlamış ve standartları belirlemiştik. Şimdi sıra…
Kariyer.Net’te DevOps Platform Dönüşüm ve Modernizasyon Süreci — 2-Altyapı Kurulum Otomasyonu & Kubespray w/ Azure DevOps Pipeline
Merhabalar, önceki yazımızda genel olarak mevcut yapıyı analiz etmiş yapılacakları planlamış ve standartları belirlemiştik. Şimdi sıra geldi yeni platform altyapımız için “Infrasctructure as Code” ile sürekli bir yaşam döngüsü halinde ve insan hatasından uzak otomasyona bağlı bir yapıya oluşturmaya.
Mevcut altyapı çalışırken, yeni altyapının kurulması, sağlamlık testlerinin yapılması ve temellerinin daha sonra yapılması olası değişiklikler için esnek bir yapıda kurulması gerekliydi. Ayrıca çok fazla sunucunun manuel olarak kurulması gerekli olacaktı. Bu sebeple yine bir yol haritası belirledik.
Grup Sunucu Kurulum Otomasyonu

Bildiğiniz üzere Kubernetes Cluster kurulumu için onlarca sunucuya ihtiyacımız oluyor. Bu sebeple bu sunucuların hızlı kurulumları bizim için önem arzediyor.
Cloud altyapımızın API’sini kullanarak, toplu sunucu kurulum ve konfigürasyon sistemi oluşturmamız gerekliydi. Bu sebeple terraformun bize uygunluğunu test etmeye başladık ancak cloud altyapı sağlayıcımızın bazı erişim güvenliği politikaları gereği ilk akla gelen terraform ile bir otomasyon oluşturmamız mümkün olmadı. Bu sebeple python kullanarak kendi yapımızı oluşturmayı denedik. Ancak bu sefer de tekrarlayan isteklerde, kullandığımız bir python kütüphanesinin SSL konusunda sorun çıkarmaya başlaması bizi bash script kullanmaya yöneltti.
- API key ile Bearer Token alacak ve environmente kaydedecek script oluşturuldu.
- Cloud üzerinden, var olan tenantlar, templateler ve vlan listemizi çekmemiz gerekliydi. Bunun için bir script yazıldı.
- API template’e uygun şekilde Vm oluşturacak CreateVM scripti yazıldı.
- Oluşturulan VM’in API linkini alcak bir FindVMLink scripti daha yazıldı daha sonra VM network’ünü ayarlamak, power on — off işlemlerini yapabilmek için gerekli olacaktı.
- BulkVMCreate scripti ile CreateVM scriptini döngü içerisinde listede verilen her yeni sunucu ayarı için çağıracak bir sistem oluşturuldu.
- Bu yapı ile template ve vlan listesinden istenen değerler alınarak ardından cpu, ram, disk, ip adres yazılarak oluşturulan listeden toplu halde sunucu kurulumlarının yapılması sağlandı.
- Bu yapı yine IaC gereği Azure Devops Pipeline’a taşındı.
Bu sistem arayüz üzerinden tek tek sunucu kurulumları yapılması yerine bir sunucu listesi yazıp çalıştırarak, kahvemizi içerken istenen sunucuların otomatik kurulmasını sağladı. Tabi kahve içecek vakitte aslında diğer işlerimize efor harcadığımızı da belirteyim :)
Kaynak: VCloud API Döküman
Kubernetes Envanterinin ve Yapılandırma Dosyalarının Oluşturulması
Kubeadm ile kurulum, her ne kadar tam kontrol sağlayan bir yöntem olsa da manuel eforun çok fazla gerektiği, kurulum sonrası bakım maliyetlerinin saatler aldığı bir kurulum yöntemi ve bizim gibi büyük bir sistemin sorumluluğunu alan diğer yandan onlarca proje üzerinde çalışan bir ekip için zaman her şey demek.
Kubespray ile yapılandırma standartlarımızı belirledik.
- NTP active
- install helm
- record LB IP adress
gibi bir çok yapılandırma standart hale getirilerek versiyonlandırıldı.
Ardından ilk kurulum testlerimizi yapmaya başladık. Bu kısım üzerinde fazla durmayacağım çünkü herkesin yapılandırma ihtiyaçları farklı olabilir.
Ancak bir dipnot düşmek isterim eğer VMWare altyapısı kullanıyorsanız, CNI olarak Flannel kullanmanızı tavsiye etmem. Çünkü flannel VXLAN yapısı ile VMWare’in vNIC olarak adlandırılan sanal ethernet kartları linux kernelda yer alan IP Checksum hesabı sebebiyle en olmadık anlarda düşebilir. Kernel mod ile bir çözüm uygulansa bile umulmadık restart gerektiren anlarda bu aklınıza gelmeyecek ve yeniden sorun oluşturacak bir durum olarak karşınıza çıkabilecektir. Böyle bir durum yaşarsanız CNI olarak Calico, Cilliumdan daha pratik bir alternatif olacaktır.
Local makineden lab cluster için kurduğumuz sunucular üzerine ansible kubespray ile cluster kurulum testlerimizi yaptık.
Kubespray kullanımı ile ilgili bir çok dökümana internet üzerinden ulaşabilirsiniz. https://github.com/kubernetes-sigs/kubespray
Bu testlerin önemi, cluster canlıya alındıktan sonra geri alınamayacak sistem geneli uygulamaların çıktılarını gözlemlemekti. Örneğin ingress controllerın kubespray ile kurulmaması, ihtiyacınıza göre nodeLocalDNS kurulumu ile cluster geneli CoreDNS’in yükünü düşürmek amacıyla node bazlı DNS Cache Proxylerin kurulması, network kesintilerinden haberdar olabilmek için netcheckher gibi internal uygulamaları kurmayı ya da kurmamayı seçebilirsiniz. Bu işlemleri tekrar tekrar yapabilmek adına kubespray içerisinde sizi dört farklı YAML dosyası bekliyor olacak.
- cluster.yaml (Kubernetes kurulumu için)
- upgrade-cluster.yaml (Kubernetes güncelleme, yapılandırma değişikliği ve linux paketlerini kontrollü güncelleme için)
- scale.yaml (Cluster'a node eklemek ve kaldırmak için)
- reset.yaml (tekrar test edebilmek amacıyla cluster'ı sunucular üzerinden kaldırmak için)
Biz burada kendimize göre bir ek kontrol mekanizması geliştirdik. Otomasyonlar her ne kadar bizi uzun uğraşlardan kurtarsa da sonuçta çalışma zamanı esnasında kapalı kutu sistemler olarak varlıklarını sürdürüyorlar. Defalarca test edilmemiş bir otomasyonun çalıştırma butonuna tıklamak ter dökmenize sebep olabilir :).
Örnek olarak kubespray inventory ile prod1-k8s kuracaksınız ve elinizde 8 adet IP adresi var. prod1-k8s clusterını kurdunuz ve ardından prod2-k8s kuracaksınız ancak inventory dosyasını yazacak olan arkadaş yanlışlıkla prod1-k8s deki bazı node IP lerini ikinciyi kopyalarken unuttu. Bu durumda siz prod2-k8s’i kurmak için sistemi çalıştırdığınızda birden bire prod1-k8s’deki iki node’un hata verdiğini ve cluster’dan koptuğunu farkedeceksiniz.
# prod1-k8s
[kube_control_plane]
# node1 ansible_host=95.54.0.12 # ip=10.3.0.1 etcd_member_name=etcd1
# node2 ansible_host=95.54.0.13 # ip=10.3.0.2 etcd_member_name=etcd2
# node3 ansible_host=95.54.0.14 # ip=10.3.0.3 etcd_member_name=etcd3
[etcd:children]
kube_control_plane
[kube_node]
# node4 ansible_host=95.54.0.15 # ip=10.3.0.4
# node5 ansible_host=95.54.0.16 # ip=10.3.0.5
# node6 ansible_host=95.54.0.17 # ip=10.3.0.6
# prod2-k8s
[kube_control_plane]
# node1 ansible_host=95.54.0.17 BU IP DUPCLICATE # ip=10.3.0.1 etcd_member_name=etcd1
# node2 ansible_host=95.54.0.18 # ip=10.3.0.2 etcd_member_name=etcd2
# node3 ansible_host=95.54.0.19 # ip=10.3.0.3 etcd_member_name=etcd3
[etcd:children]
kube_control_plane
[kube_node]
# node4 ansible_host=95.54.0.20 # ip=10.3.0.4
# node5 ansible_host=95.54.0.21 # ip=10.3.0.5
# node6 ansible_host=95.54.0.22 # ip=10.3.0.6
İşte yukarıdaki durumun önüne geçmek için kubespray’in orjinal cluster.yaml dosyasının önüne clusterIsEmpty.yaml ile tüm IP’lerin üzerinde var olan bir kubernetes kurulumu var mı yok mu diye kontrol ediyoruz.
- name: Get service status using shell command
hosts: all
tasks:
- name: Check Kubernetes already active?
shell: systemctl is-active kubelet
register: service_status_systemctl
ignore_errors: true
- name: Check Servers Hostname
shell: hostname
register: server_hostname
- name: Kurulmak istenen sunucularda cluster mevcut mu?
debug:
msg:
- "Kubelet Service status: {{ service_status_systemctl.stdout }} in {{ server_hostname.stdout }}"
- "MEVCUT CLUSTER BULUNDU, YİNE DE KURMAK İSTİYORSANIZ ÖNCE CLUSTER RESETLEYİN!"
failed_when: service_status_systemctl.rc == 0
- assert: { that: "service_status_systemctl.rc != 0" }

Kubesprayin Azure Devops Pipeline’a Bağlanarak IaC Sağlanması
Localde testlerimizi tamamlayıp yapılandırmalarımıza kesin karar verdikten sonra ve kendi özelleştirmelerimizi tamamladıktan sonra kubespray Docker imajını kullanarak, bir Azure Pipeline oluşturduk.
Sonda yer alan cluster.yaml yerine upgrade-cluster.yaml yazılırsa güncelleme pipeline’ı da kurulmuş olacaktır. Burada bir örnek vererek konuyu uzatmıyorum.
pool:
name: Ansible
jobs:
- job: initKubernetesCluster
timeoutInMinutes: 120
steps:
- script: |
git checkout
displayName: 'Checkout Code'
- task: DownloadSecureFile@1
name: yourSSHkey
displayName: 'Download yourSSHkey'
inputs:
secureFile: 'yourSSHkey'
- script: |
echo Installing $(yourSSHkey.secureFilePath) to directory...
sudo chown root:root $(yourSSHkey.secureFilePath)
sudo chmod 600 $(yourSSHkey.secureFilePath)
sudo cp $(yourSSHkey.secureFilePath) ./yourSSHkey
displayName: 'Setup SSH Key'
- script: |
ls -la
ls -la "$(pwd)"/inventory/$(cluster_name)-k8s/
docker pull quay.io/kubespray/kubespray:v$(ks-version)
docker run --rm -t --name kubeinit --mount type=bind,source="$(pwd)"/inventory,dst=/inventory \
--mount type=bind,source="$(pwd)"/yourSSHkey,dst=/root/.ssh/yourSSHkey \
quay.io/kubespray/kubespray:v$(ks-version) ansible-playbook -i /inventory/$(cluster_name)-k8s/$(cluster_name)-k8s.ini --private-key /root/.ssh/yourSSHkey --limit=$(node) cluster.yml
displayName: 'Run Ansible Playbook'
- script: docker stop kubeinit
condition: canceled()
- Öncelikle ansible yüklü sunucularda çalışmasını belirtiyoruz. Kubespray aslında kubernetes kurulumunun ansible playbooklar ile otomatize edilmiş haline verilen isim.
- Repoda düzenlenmiş kod checkout ediliyor.
- Sunuculara şifre ile değil SSH key ile bağlanıyoruz bu yüzden SSH Key, Azure Devops SecureFile storage’dan çekiliyor.
- Ardından SSH Key ansible yüklü sunucumuza çekiliyor.
- Belirlediğimiz kubespray versiyonunun imajı quay.io dan çekiliyor. Inventory klasörü ve SSH Key container içerisine mount ediliyor.
- Pipeline çalıştırma esnasında vereceğimiz Pipeline Variable cluster_name ile doğru cluster inventory komuta getirilerek cluster.yaml çalıştırılır.
- — limit node kısmı upgrade_cluster.yaml tetikleneceği sırada Pipeline Variable dan verilecek node isimleri ile upgrade’i limitlendirmek amaçlı eklenmiş bir kısım, aslında cluster.yaml tetikleneceği sırada bizim için önemli değil.
- Son olarak acil olarak pipeline cancel edilirse arka planda docker çalışmaya devam etmesin diye “docker stop kubeinit” komutu ile docker çalışması da acil olarak kesiliyor.
Bilgilendirici bir yazı olduğunu umuyorum sonraki yazıda görüşmek üzere …
메타데이터
- post_id
- ca0f174d32d8
- slug
- kariyer-nette-devops-platform-dönüşüm-ve-modernizasyon-süreci-2-altyapı-kurulum-otomasyonu-ca0f174d32d8
- url
- https://medium.com/kariyertech/kariyer-nette-devops-platform-d%C3%B6n%C3%BC%C5%9F%C3%BCm-ve-modernizasyon-s%C3%BCreci-2-altyap%C4%B1-kurulum-otomasyonu-ca0f174d32d8
- canonical_url
- https://medium.com/kariyertech/kariyer-nette-devops-platform-d%C3%B6n%C3%BC%C5%9F%C3%BCm-ve-modernizasyon-s%C3%BCreci-2-altyap%C4%B1-kurulum-otomasyonu-ca0f174d32d8
- author_url
- https://medium.com/@vahitustaoglu
- status
- ok
- fetched_at
- 2026-07-20 21:03:38