Bizler her geçen gün daha iyi bir teknik altyapı için birlikte çalışıyoruz. Web, mobil veya masaüstü uygulama örneklerinin, servisler ve sunucuların en uygun şekilde canlı ortama geçişi için çeşitli araçlar ve yöntemler kullanıyoruz.

Bazı durumlarda sıfırdan onlarca sunucu veya ortam ayaklandırıp her birine aynı programları kuruyor, izinleri veriyor ve protokol erişimleri sağlıyoruz. Zaman içerisinde yeni eklenen bileşenler de tekrarlı bir şekilde aynı süreçlerden nasibini alıyor.

Bu yazıda tüm bu işlemler için Infrastructure as Code (IaC) - Kod Olarak Alt Yapı ve IT (Bilgi Teknolojileri) otomasyon aracı Ansible' ı kullanarak örnek bir uygulama ve mimari yapı üzerinden yapılandırma yönetimi çözümü üretmeye çalışacağız.

Kod olarak alt yapı; bir işi yapmak üzere belli özelliklere, programlara ve izinlere sahip olması beklenen bilgisayarların etkileşimli yapılandırma araçları yerine kod ile veya çalıştırıcısına özel hazırlanmış dosyalar aracılığıyla istenilen özelliklere sahip olması ve yönetilmesi olarak ifade edilebilir.

Ansible; belirli dosya tiplerinde tanımlanmış görevlerin veya rollerin, envanterde yer alan bilgisayarlar (hosts) üzerinde çalıştırılarak yerine getirilmesini sağlar. Böylece bir sisteme eklenecek yeni bir bilgisayarı, güncellenecek bir servisi veya yüklenecek yeni bir programı ortamlarımıza uygun yapılandırmalar ile adapte eder, hazır hale getirir.

Hazırladığım Ansible projesi için; (GitHub)
Docker, sanal makine sağlayıcısı - provizyon görevini yerine getirirken docker-compose ile de çoklu konteyner yönetimini gerçekleştireceğiz. Bu sayede Ansible modül ve görevlerini belirli sunucu gruplarında kolaylıkla çalıştırıp sonuçlarını kontrol edebileceğiz.

Bu proje ile müzik listelerini altüst eden albümlere ait bilgileri HTTP API olarak sunan uygulamayı üç sunucuda yayına alacağız. Çalışmaya başlayan her uygulama Consul' a kendini kayıt edecek ve uygulamalar MongoDB veri tabanından okuma işlemi yapacak.

Ansible Lab


Ansible Yönetim Bilgisayarı - Ansible Controller

Envantere kayıtlı tüm bilgisayarlara ssh üzerinden bağlanıp görev ve modülleri çalıştıracak olan işlemciye Ansible Yönetim Bilgisayarı adını verelim.

Envanter; sunucu - host grup bilgilerini belirttiğimiz tercihen ansible_hosts isimli dosyada tanımlanan kayıtları ifade eder. Bu dosya; Ansible Yönetim Bilgisayarı için sunucu adlarını, IP adreslerini, ssh anahtar bilgilerini ve daha birçok değişkeni temin edebilir.

Örnek içeriği şu şekildedir:

[api]
api01
api02
api03

[db]
mongo

[all:vars]
ansible_user=root
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_private_key_file=~/.ssh/AnsibleLabKey

Bu dosyada sunucu isimlerinin docker-compose.yml dosyasında belirtilen konteyner isimleriyle aynı olduğuna dikkat ediniz. [all:vars] ifadesiyle belirtilen değişken ikililerinin tüm sunucular için geçerli olmasını sağlayabiliriz.

Bu proje için planladığımız Ansible Yönetim Bilgisayarının diğer tüm ortam sunucularına bağlanabilmesi için bir şifreleme anahtarı oluşturarak başlayabiliriz.

ssh-keygen -t rsa -b 1024 -C "AnsibleLabKey"

Şifre (passphrase) girmeden oluşturduğumuz özel ve genel erişimli güvenlik anahtar dosyalarını kullanmak üzere proje dizininde muhafaza edelim. Daha sonra genel erişimli güvenlik anahtarını (AnsibleLabKey.pub) ssh bağlantısı için tüm ortam sunucularının authorized_keys isimli dosyasına eklememiz gerekecek. (Bu kısmı Dockerfile ile yapacağız).

Bu aşamadan sonra Ansible Yönetim Bilgisayarını hazırlamak için buradaki ansible/Dockerfile'ı kullanabiliriz.

docker build -t ansible-lab -f ansible/Dockerfile

Proje ana dizininde iken yukarıdaki komut çalıştırıldığında özel güvenlik anahtarı bilgileri aktarımı, ssh ve Ansible kurulumu yapılmış hazır bir docker imajı elde etmiş oluruz.

Ansible' ı hazırladığımıza göre sunucular ve gereksinimleri üzerine çalışmaya başlayabiliriz.

Sunucular

Ansible sunuculara ssh ile bağlanacağından oluşturacağımız sunucu imajları için openssh-server programını ve python programlama dili kurulumlarını yapmalıyız.

Bunun için uygulamamızı yayınlayacağımız sunucuları için buradaki api/Dockerfile'ı hazırladım.

docker build -t api-lab -f api/Dockerfile .

Bu komut ile api-lab isimli docker imajını oluşturabiliriz.

MongoDB veri tabanı için kullanacağımız db/Dockerfile dosyası ile

docker build -t mongo-lab -f db/Dockerfile .

komutunu çalıştırarak mongo-lab isimli imajı hazırlamış oluruz. Consul için varsayılan Docker imajını olduğu haliyle kullanabiliriz.

Lab ortamında oluşturacağımız birden fazla docker konteynerı için docker-compose aracını kullanacağımızı belirtmiştik. Bunun için proje ana dizininde yer alan docker-compose.yml isimli dosya ile az önce oluşturduğumuz imajlar üzerinden servisler tanımlamamız yeterlidir. Bu araç ile farklı işleri yapmak üzere tasarladığımız servislerin işlem ve kaynak kapasitelerini yönetebilir ve çalıştırabiliriz.

docker-compose up -d

komutu ile docker-compose.yml dosyasında az önce oluşturduğumuz imajlar ile belirlediğimiz servisleri başlatalım.

DockerComposeUpView

Bu aşamaya kadar yaptığımız ayarların doğru çalışıp çalışmadığını ve sunucularımızın erişim durumlarını Ansible ping modülü ile kontrol edebiliriz. Bunun için öncelikle envanter bilgileri, uygulama dağıtım paketini, servis kayıtlarını ve app.yml gibi gerekli dosyaları tuttuğumuz playbooks isimli klasörü az önce çalıştırdığımız ansible isimli konteynera kopyalayıp shell ara yüzüne bağlanalım:

docker cp playbooks ansible:/home/

docker exec -i -t ansible /bin/bash

DockerCopyAndPing

/home/playbooks# ansible all -m ping -i ansible_hosts

Bu komut ile host dosyasında tanımlı tüm sunucular için Ansible ping modülünün komut satırından bir defaya mahsus çalıştırılması sağlanır. Ansible varsayılan olarak birçok modül barındırır ve bunların ping, apt, file, copy, service vb. isimleriyle sıkça kullanacaklarımıza yeri geldikçe değineceğim. Resmi sitesi ve dokümantasyon kısmından modüller hakkında detaylı bilgilere ulaşabilirsiniz.

Ansible ve özel Docker imajlarımıza ait ayarları tamamlayıp ping modülü başarıyla çalıştığına göre bir sonraki adıma geçebiliriz.

Web sunucuları:

  • Nginx - HTTP isteklerini karşılayıp reverse-proxy olarak çalışacak.
  • .NET Core web uygulaması istekleri işleyecek.
  • Uygulamamız için daemon kaydı oluşturulup çalışma sürekliliği sağlanacak.

Veri tabanı sunucusu:

  • 27017 portundan ve tüm IP adreslerinden hizmet verecek şekilde çalışacak.
  • db/musicstore.archive isimli örnek veri tabanı yedeği varsayılan olarak yüklü gelecek.

Consul:

  • Ek bir yapılandırma gerekmeden servis kayıt isteklerini alıp uygulama durum (health check) bilgilerini sağlayacak.

Yukarıda saydığım adımların Ansible tarafından belirtilen sunucularda oynatılması - çalıştırılması için playbooks/app.yml isimli dosyayı hazırladım. Sunucuları ilgilendiren işlemleri, scriptleri ve senaryoları tanımladığımız bu dosyalara Ansible için Playbooks deniyor.

Bu dosya hosts: db ve hosts: api bölümleriyle iki kısımdan oluşuyor. Bu kısımların, host tanımlarını yaptığımız dosyada (ansible_hosts) belirtilen db ve api gruplarını işaret ettiği kolayca anlaşılabilir.

Bu gruplar için belirlediğimiz görevler tasks kısmında isim ve modül bilgisi içerecek şekilde sıralanır.

- name: Copy default mongodb config file
    copy: src=/etc/mongod.conf.orig dest=/etc/mongod.conf remote_src=yes

Yukarıdaki satır ile db grubu için sunucu tarafında yer alan mongod.conf.orig isimli dosya, mongod.conf adıyla aynı dizine kopyalanır. İlgili dosyanın modülün çalıştırıldığı bilgisayarda olduğunu remote_src=yes parametresiyle belirtmiş oluruz.

Bir diğer komut ise;

- name: Download the dep file
    get_url: 
      url: https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb
      dest: /home/packages-microsoft-prod.deb

şeklinde eklenerek ilgili adresten dotnet-core runtime kurulumu için gerekli dosyanın daha sonraki adımlarda kullanılmak üzere ilişkili dizine indirilmesi sağlanır.

Başka bir örnekte ise;

- name: Install nginx
    apt: name=nginx state=present update_cache=yes

Apt paket yöneticisi kullanılarak nginx web sunucusu programının kurulması ve update_cache parametresi ile paketi yüklemeden önce apt-get update komutunun çalıştırılması sağlanır.

App.yml dosyasında birbirine benzer birçok modül-komut kullanımı görebilirsiniz. Burada tanımlı diğer görevler modül ismi ile okunduğu şekilde yorumlanabilir. Her birini ayrı ayrı burada detaylandırmaya gerek olmadığını düşünüyorum. Bunun yerine Ansible resmi sitesinde geçen modül dokümantasyonları incelenebilir.

Ansible' ın bu dosya ile çalışma mantığı basitçe şu şekilde olacaktır:

  • Görevler modülleri çağırır.
  • Görevler birbirini ardına - sıralı şekilde çalışır.
  • İşleyiciler (handlers) görevler tarafından tetiklenir ve bir defa olarak oynatılan adımların sonunda çalışır.

Bu proje için geliştirdiğimiz dotnet-core uygulamasına ait kaynak kodları çalışma dizininde api/app/Api.Hosting isimli klasör altında bulunduracağız. Yaptığımız geliştirmeler tamamlandıkça şu komut ile:

dotnet publish -c Release -o bin/hosting api/app/Api.Hosting/Api.Hosting.csproj

uygulama sürümü için hazır derlemeyi oluşturup

tar -C $(pwd)/api/app/Api.Hosting/bin/hosting/ -zcvf playbooks/app.tar.gz .

komutu ile de ilgili dosyaların paketlenmesini sağlayacağız. Böylelikle Ansible için oluşturduğumuz playbooks isimli klasör altında en güncel uygulama dağıtım sürümü olacak. GitHub, GitLab, VSTS gibi bulut tabanlı kod depolarının kullanımı daha sonraki yazılarda detaylandıracağız.

Uygulama dosyaları ile birlikte playbooks isimli klasörü Ansible Yönetim Bilgisayarına kopyaladıktan sonra app.yml içerisindeki tüm sıralı görevlerin çalıştırılması için

/home/playbooks# ansible-playbook app.yml -i ansible_hosts

komutunu çalıştırmalıyız. Bu sayede tüm sunucularda sırasıyla çalışan işlem ve adımlara dair detaylı bilgiler verilecek ve başarıyla çalıştıktan sonra şu görüntüyü elde etmiş olacaksınız.

AnsiblePlayRecap

İşlemler tamamlandığında uygulamaya ait HTTP adreslerini ve Consul ara yüzünü tarayıcıda kontrol edebiliriz.

FullServiceInfo

Öncelikle Ansible ile ilgili kısımları iyi kavramakta fayda var. Daha sonra ki yazılarda docker-compose ve swarm ile scale ve replica özellikleri kullanılarak bilgisayar sayılarının otomatik olarak arttırılmasını deneyip ayrıca bir istemci uygulamasının (Web, SPA) yük dengeleyici kullanarak bu servislere ulaşmasını sağlayamaya çalışacağız.

Ansible kendi içerisinde veya haricen geliştirilen birçok hazır modül, görev ve rol sunmaktadır. Elbette docker ile entegre olarak çalışabilen docker_container, docker_image ve docker_servis isimli Ansible modüllerini değerlendirebiliriz. Bu yazı dizisinde önceliğimiz Docker ve Ansible' ın yönetim, test, modüller vb. özelliklerini ve kabiliyetlerini kavramak sonrasında Production için bu araçları rahatlıkla kullanabilmeye hazırlanmak olacaktır.

Vagrant' ın da Ansible'ı öğrenmek ve ilerletmek için iyi bir araç olduğu söyleniyor fakat ben yatkınlığım ve bana kolay gelişi sebebiyle Docker'ı tercih ettim.

Faydalı olması dileğiyle. Bir de Sensible Soccer vardı :) efsaneyi anmadan olmaz.