Modern yazılım geliştirme ve dağıtım süreçlerinde otomasyon, hem zaman tasarrufu hem de tutarlılık açısından kritik bir rol oynar. Bu kapsamlı rehberde, popüler otomasyon aracı Ansible’ı kullanarak Ubuntu sunucularına Docker’ı nasıl hızlı, verimli ve tekrarlanabilir bir şekilde kuracağınızı adım adım öğreneceksiniz. Manuel kurulumun getirdiği zorlukları aşarak, altyapı yönetim süreçlerinizi kolaylaştırmak ve modern yazılım mimarilerine sorunsuz bir geçiş yapmak için gerekli tüm pratik bilgileri ve kod örneklerini bu makalede bulacaksınız.
Neden Ansible ile Docker Kurulumu Yapmalıyız?
Günümüzün hızla değişen teknoloji dünyasında, yazılım geliştirme ve dağıtım süreçleri hiç olmadığı kadar dinamik hale gelmiştir. Uygulamalarımızı konteynerize ederek daha izole, taşınabilir ve ölçeklenebilir hale getirmek, sektörde standart bir yaklaşım haline gelmiştir. Bu noktada Docker, konteyner teknolojisinin öncüsü olarak karşımıza çıkar. Ancak Docker’ı tek bir sunucuya manuel olarak kurmak nispeten basit olsa da, birden fazla sunucuya veya sürekli değişen ortamlara tutarlı bir şekilde dağıtmak, karmaşık ve hataya açık bir süreç olabilir. İşte tam da bu noktada Ansible gibi bir otomasyon aracı devreye girer ve manuel süreçlerin getirdiği tüm zorlukları ortadan kaldırır.
Manuel kurulumlar, her sunucuda farklı adımların uygulanmasına veya gözden kaçan detaylara yol açarak ortamlar arasında tutarsızlıklar yaratabilir. Bu tutarsızlıklar, geliştirme, test ve üretim ortamlarında beklenmedik davranışlara, hata ayıklama süreçlerinin uzamasına ve en önemlisi zaman kaybına neden olabilir. Ayrıca, güvenlik güncellemeleri veya yeni sürümler çıktığında, her sunucuya tek tek bağlanıp aynı işlemleri tekrarlamak, özellikle büyük altyapılarda ciddi bir iş yükü oluşturur. Bu durum, hem operasyonel maliyetleri artırır hem de insan hatası riskini yükseltir. Dahası, el ile yapılan işlemler genellikle belgelenmesi zor olduğundan, ekip üyeleri arasında bilgi aktarımı da zorlaşır.
Ansible, bu sorunlara zarif ve etkili bir çözüm sunar. Agent-less (aracı gerektirmeyen) mimarisi sayesinde yönetilen sunuculara herhangi bir yazılım yüklemeye gerek kalmadan SSH üzerinden iletişim kurar. Bu özellik, kurulum ve yapılandırma süreçlerini basitleştirir ve güvenlik risklerini azaltır. Ansible playbook’ları, YAML formatında yazılmış basit ve okunabilir dosyalardır. Bu playbook’lar, belirli bir görevi (örneğin Docker kurulumu) tanımlayan bir dizi adımdan oluşur. Bu sayede, tüm kurulum adımları kod olarak belgelenmiş olur ve tekrarlanabilirlik garanti altına alınır. Bir playbook’u defalarca çalıştırmak, her zaman aynı sonucu verir, çünkü Ansible’ın idempotent (etkisiz tekrarlama) yapısı, bir görevin yalnızca gerekli olduğunda uygulanmasını sağlar. Yani Docker zaten kuruluysa, Ansible yeniden kurmaya çalışmaz, sadece mevcut durumu doğrular.
Ansible’ın ölçeklenebilirlik yeteneği de göz ardı edilemez. İster tek bir sunucuya, ister yüzlerce sunucuya Docker kurmanız gereksin, aynı playbook’u kullanarak tüm ortamınızı saniyeler içinde yapılandırabilirsiniz. Bu, özellikle bulut ortamlarında dinamik olarak büyüyen altyapılar için paha biçilmez bir avantajdır. Yeni bir sunucuya ihtiyacınız olduğunda, Ansible playbook’unuzu çalıştırarak saniyeler içinde Docker kurulu, üretime hazır bir makine elde edebilirsiniz. Böylece, geliştiriciler ve operasyon ekipleri, altyapı kurulumuyla uğraşmak yerine, asıl işlerine, yani uygulama geliştirmeye ve dağıtmaya odaklanabilirler. Özetle, Ansible ile Docker kurulumu, hem verimliliği artıran hem de olası hataları minimize eden modern bir yaklaşımdır. Bu makale boyunca, bu güçlü ikilinin nasıl bir araya getirileceğini detaylı bir şekilde inceleyeceğiz.
Temel Kavramlar: Ansible ve Docker’ı Yakından Tanıyalım
Otomasyon ve konteynerleşme dünyasına adım atmadan önce, bu iki temel teknolojinin ne anlama geldiğini ve nasıl çalıştığını anlamak kritik öneme sahiptir. Ansible, altyapı otomasyonu için tasarlanmış bir araçken, Docker uygulama konteynerleşmesi için bir platformdur. Her ikisi de modern DevOps pratiklerinin vazgeçilmez bileşenleridir ve birlikte kullanıldıklarında muazzam bir sinerji yaratırlar. Bu bölümde, bu iki teknolojinin temel prensiplerini ve neden bu kadar popüler olduklarını detaylı bir şekilde ele alacağız.
Ansible Nedir ve Nasıl Çalışır?
Ansible, Red Hat tarafından geliştirilen açık kaynaklı bir BT otomasyon motorudur. Konfigürasyon yönetimi, uygulama dağıtımı, görev otomasyonu gibi çeşitli alanlarda kullanılır. Ansible’ı diğer otomasyon araçlarından ayıran en önemli özelliklerden biri, “agent-less” mimarisidir. Yani, yönetilen sunuculara herhangi bir özel yazılım veya “agent” yüklemenize gerek kalmaz. Bunun yerine, SSH protokolü üzerinden uzaktan bağlantı kurar ve Python tabanlı modüller aracılığıyla görevleri yerine getirir. Bu, kurulumu ve bakımı oldukça basitleştirir, çünkü ek bir bağımlılık veya servis yönetimi yükü getirmez.
Ansible, bir “kontrol düğümü” (control node) üzerinden çalışır. Bu kontrol düğümü, Ansible’ın kurulu olduğu ve playbook’ların çalıştırıldığı makinedir. Yönetilen sunuculara ise “yönetilen düğümler” (managed nodes) veya “hedef makineler” denir. Ansible, bu düğümleri bir “envanter dosyası” (inventory file) aracılığıyla tanımlar. Bu dosya, yönetilecek sunucuların IP adreslerini, ana bilgisayar adlarını ve bağlantı bilgilerini içerir. Playbook’lar ise, YAML formatında yazılmış, okunması kolay dosyalardır ve belirli bir görevi gerçekleştirmek için adım adım talimatları barındırır. Her bir adım, bir “görev” (task) olarak adlandırılır ve Ansible’ın yerleşik modüllerinden birini kullanarak belirli bir işlemi (örneğin paket yükleme, servis başlatma, dosya kopyalama) gerçekleştirir. Ansible’ın “idempotent” yapısı, bir playbook’u birden fazla kez çalıştırsanız bile, sistemin istenen duruma gelmesini ve bu durum zaten mevcutsa herhangi bir değişiklik yapmamasını sağlar. Bu özellik, özellikle altyapı yönetimi ve tutarlılık açısından çok değerlidir.
Docker Nedir ve Konteynerleşme Neden Önemli?
Docker, uygulamaları “konteyner” adı verilen izole edilmiş ve taşınabilir birimler içinde paketlemek için kullanılan açık kaynaklı bir platformdur. Konteynerler, uygulamayı ve tüm bağımlılıklarını (kütüphaneler, ayarlar vb.) bir araya getirerek, farklı ortamlarda tutarlı bir şekilde çalışmasını sağlar. Geleneksel sanal makineler (VM’ler) ile karşılaştırıldığında, konteynerler çok daha hafif ve hızlıdır. Bir VM, kendi işletim sistemini içerirken, konteynerler ana bilgisayarın işletim sistemi çekirdeğini paylaşır. Bu, konteynerlerin saniyeler içinde başlatılabilmesini ve çok daha az kaynak tüketmesini sağlar.
Konteynerleşmenin önemi birkaç temel noktada toplanır. Birincisi, “çalışırsa, her yerde çalışır” prensibini mümkün kılar. Geliştirme ortamınızda çalışan bir uygulama, test ve üretim ortamlarında da aynı şekilde çalışacaktır, çünkü tüm bağımlılıkları konteyner içinde paketlenmiştir. Bu, “benim makinemde çalışıyordu” sendromunu ortadan kaldırır ve geliştirme ile operasyon ekipleri arasındaki sürtüşmeyi azaltır. İkincisi, izolasyon sağlar. Her konteyner, kendi kaynaklarına (CPU, bellek, ağ) sahip ayrı bir işlem olarak çalışır ve diğer konteynerlerden izole edilmiştir. Bu, bir uygulamanın diğerini etkilemesini engeller ve güvenlik risklerini azaltır. Üçüncüsü, hızlı dağıtım ve ölçeklenebilirlik sunar. Konteynerler hızla başlatılıp durdurulabildiği için, uygulamaların dağıtımı ve yatay ölçeklenmesi çok daha kolay hale gelir. Bu da modern mikroservis mimarileri ve bulut tabanlı uygulamalar için ideal bir çözüm sunar. Docker, bu avantajları sağlayarak yazılım geliştirme, test etme ve dağıtma şeklimizi kökten değiştirmiştir. Ansible ile Docker’ı bir araya getirmek, bu avantajları otomatikleştirilmiş ve tekrarlanabilir bir süreçle elde etmemizi sağlar.
Ansible Ortamını Hazırlama: Kontrol Düğümünüzü Kurma
Ansible ile Docker kurulumuna başlamadan önce, otomasyon sürecini yönetecek olan kontrol düğümünü (control node) doğru bir şekilde yapılandırmamız gerekiyor. Bu kontrol düğümü, Ansible’ın kurulu olduğu ve tüm playbook’ları çalıştıracağımız makinedir. Yönetilen sunucumuz olarak da Ubuntu işletim sistemine sahip bir makineye ihtiyacımız olacak. Bu bölüm, kontrol düğümünüzü nasıl kuracağınızı ve yönetilen sunucuyla güvenli bir bağlantı kurmak için gerekli adımları detaylandıracaktır.
Ubuntu Üzerinde Ansible Kurulumu
Kontrol düğümü olarak kullanacağımız Ubuntu makinesine Ansible’ı kurmanın birkaç yolu vardır. En yaygın ve önerilen yöntemlerden biri, işletim sisteminin paket yöneticisi olan APT’yi kullanmaktır. Bu yöntem, Ansible’ın bağımlılıklarıyla birlikte kolayca kurulmasını sağlar.
İlk olarak, sisteminizin paket listesini güncelleyerek başlayın:
sudo apt update
sudo apt upgrade -y
Ardından, Ansible’ı aşağıdaki komutla kurabilirsiniz:
sudo apt install ansible -y
Kurulum tamamlandıktan sonra, Ansible’ın doğru bir şekilde kurulduğundan emin olmak için sürümünü kontrol edebilirsiniz:
ansible --version
Bu komut, Ansible sürümünü, Python sürümünü ve diğer yapılandırma bilgilerini gösterecektir. Eğer pip (Python paket yöneticisi) ile kurulumu tercih ediyorsanız, öncelikle pip’i kurmanız gerekebilir:
sudo apt install python3-pip -y
pip3 install ansible
Her iki yöntem de geçerlidir, ancak APT ile kurulum genellikle daha kolaydır ve sisteminizle daha iyi entegre olur.
SSH Anahtar Çifti Oluşturma ve Yönetilen Sunucuya Kopyalama
Ansible, yönetilen sunuculara SSH üzerinden bağlanır. Bu bağlantının güvenli ve parola gerektirmeyen bir şekilde gerçekleşmesi için SSH anahtar çifti kullanmak en iyi pratiktir. Kontrol düğümünüzde bir SSH anahtar çifti oluşturmanız ve genel anahtarınızı yönetilen Ubuntu sunucunuza kopyalamanız gerekecektir.
Kontrol düğümünüzde SSH anahtar çifti oluşturmak için aşağıdaki komutu kullanın:
ssh-keygen -t rsa -b 4096
Bu komut, size anahtar dosyasının kaydedileceği yeri soracaktır (varsayılan olarak ~/.ssh/id_rsa). Bir parola (passphrase) belirlemeniz istenecektir; güvenliği artırmak için bir parola belirleyebilirsiniz, ancak otomasyon senaryolarında parola kullanmamak da yaygındır. Parola kullanmamak için Enter tuşuna basarak boş bırakabilirsiniz. Bu işlem, ~/.ssh/id_rsa (özel anahtar) ve ~/.ssh/id_rsa.pub (genel anahtar) dosyalarını oluşturacaktır.
Şimdi, genel anahtarınızı yönetilen Ubuntu sunucunuza kopyalamamız gerekiyor. Bunu ssh-copy-id komutuyla kolayca yapabiliriz. Yönetilen sunucunun IP adresini veya ana bilgisayar adını ve kullanıcı adını (örneğin, ubuntu kullanıcısı) bilmeniz gerekmektedir:
ssh-copy-id kullanıcı_adı@yönetilen_sunucu_ip_adresi
Örneğin, ssh-copy-id ubuntu@192.168.1.100. Bu komut, ilk bağlantıda sizden yönetilen sunucunun parolasını isteyecek ve genel anahtarınızı ~/.ssh/authorized_keys dosyasına ekleyecektir. İşlem tamamlandıktan sonra, artık parola girmeden SSH ile yönetilen sunucunuza bağlanabilmelisiniz.
Envanter Dosyasının (hosts) Oluşturulması ve Bağlantı Testi
Ansible’ın yöneteceği sunucuları bilmesi için bir envanter dosyasına ihtiyacı vardır. Varsayılan olarak, Ansible /etc/ansible/hosts dosyasını kullanır, ancak genellikle proje bazlı envanter dosyaları oluşturmak daha esnektir. Projenizin kök dizininde hosts adında bir dosya oluşturalım:
mkdir ansible-docker
cd ansible-docker
touch hosts
hosts dosyasının içine yönetilen sunucunuzun bilgilerini ekleyin. Örneğin:
# hosts dosyası içeriği
[docker_sunuculari]
yönetilen_sunucu_ip_adresi ansible_user=kullanıcı_adı ansible_python_interpreter=/usr/bin/python3
Burada [docker_sunuculari] bir grup adıdır. yerine sunucunuzun IP adresini veya ana bilgisayar adını yazın. ansible_user parametresi, Ansible’ın SSH ile bağlanmak için kullanacağı kullanıcı adını belirtir (örneğin, ubuntu). ansible_python_interpreter ise yönetilen sunucudaki Python 3 yolunu belirtir, çünkü birçok Ansible modülü Python’a ihtiyaç duyar.
Şimdi, Ansible’ın yönetilen sunucunuza başarılı bir şekilde bağlanıp bağlanmadığını test edelim. Bunun için ping modülünü kullanabiliriz:
ansible -i hosts docker_sunuculari -m ping
Eğer her şey yolundaysa, şöyle bir çıktı almalısınız:
yönetilen_sunucu_ip_adresi | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
Bu “pong” yanıtı, Ansible’ın yönetilen sunucunuzla başarılı bir şekilde iletişim kurduğunu gösterir. Artık kontrol düğümünüz hazır ve Docker kurulum playbook’umuzu yazmaya başlayabiliriz.
Adım Adım Docker Kurulum Playbook’u Oluşturma
Ansible ortamımızı başarıyla hazırladığımıza göre, şimdi asıl işe, yani Docker’ı Ubuntu sunucumuza otomatik olarak kuracak Ansible playbook’unu yazmaya başlayabiliriz. Bu playbook, Docker’ın resmi belgelerinde belirtilen adımları takip ederek, güvenli ve tutarlı bir kurulum sağlayacaktır. Playbook’umuzu parçalara ayırarak, her bir görevin ne işe yaradığını ve neden önemli olduğunu açıklayacağız. Bu sayede, sadece kodu kopyalamakla kalmayacak, aynı zamanda arkasındaki mantığı da anlamış olacaksınız.
Playbook’umuzu docker_install.yml adıyla oluşturalım:
# docker_install.yml
---
- name: Ubuntu'ya Docker Kurulumu
hosts: docker_sunuculari
become: yes # Görevleri root yetkileriyle çalıştırmak için
tasks:
- name: Sistem paket listesini güncelle
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600 # Önbelleği 1 saat geçerli tut
- name: Gerekli APT bağımlılıklarını kur
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- software-properties-common
- name: Docker'ın resmi GPG anahtarını ekle
ansible.builtin.apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Docker stabil deposunu ekle
ansible.builtin.apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable
state: present
update_cache: yes
- name: Docker CE, Docker CLI ve containerd.io paketlerini kur
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- docker-ce
- docker-ce-cli
- containerd.io
- name: Docker servisini başlat ve başlangıçta etkinleştir
ansible.builtin.systemd:
name: docker
state: started
enabled: yes
- name: Mevcut kullanıcıyı docker grubuna ekle
ansible.builtin.user:
name: "{{ ansible_user }}"
groups: docker
append: yes
when: ansible_user != 'root' # Eğer root kullanıcısı değilse ekle
- name: Kullanıcı grubu değişikliğini uygulamak için sistemi yeniden başlat (isteğe bağlı)
ansible.builtin.reboot:
when: ansible_user != 'root' # Sadece root olmayan kullanıcılar için gerekli olabilir
- name: Docker kurulumunu doğrula (hello-world çalıştır)
ansible.builtin.command: docker run hello-world
register: docker_hello_world_output
changed_when: false # Bu komut sistemi değiştirmez
- name: Docker hello-world çıktısını göster
ansible.builtin.debug:
var: docker_hello_world_output.stdout_lines
Gerekli Önkoşulları Kurma ve Sistem Güncelleme
Playbook’umuzun ilk görevi, yönetilen sunucunun paket listesini güncellemektir. Bu, her zaman en son paket bilgilerine sahip olmamızı ve olası bağımlılık sorunlarını önlememizi sağlar. update_cache: yes parametresi, apt update komutunu çalıştırmaya eşdeğerdir. cache_valid_time ise önbelleğin ne kadar süre geçerli kalacağını belirler, bu da sık sık playbook çalıştıranlar için performansı artırabilir.
- name: Sistem paket listesini güncelle
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600 # Önbelleği 1 saat geçerli tut
Ardından, Docker’ın APT deposunu eklemek ve paketlerini kurmak için gerekli olan bazı temel bağımlılıkları yüklüyoruz. Bu bağımlılıklar arasında HTTPS üzerinden depolara erişim sağlayan apt-transport-https, güvenlik sertifikaları için ca-certificates, dosyaları indirmek için curl, GPG anahtarları için gnupg-agent ve add-apt-repository komutu için software-properties-common bulunur. loop yapısı, aynı görevi farklı öğelerle tekrarlamamızı sağlar, bu da kodu daha temiz hale getirir.
- name: Gerekli APT bağımlılıklarını kur
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- apt-transport-https
- ca-certificates
- curl
- gnupg-agent
- software-properties-common
Docker APT Deposunu Ekleme
Docker’ı resmi depodan kurmak, her zaman en güncel ve güvenli sürüme sahip olmamızı sağlar. Bu işlem iki adımdan oluşur: Docker’ın resmi GPG anahtarını sisteme eklemek ve Docker deposunu APT kaynaklarımıza eklemek. GPG anahtarı, indirdiğimiz paketlerin gerçekten Docker tarafından sağlandığını doğrulamamızı sağlar ve güvenlik açısından kritik öneme sahiptir.
- name: Docker'ın resmi GPG anahtarını ekle
ansible.builtin.apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
Anahtarı ekledikten sonra, Docker stabil deposunu APT kaynak listemize ekliyoruz. ansible_distribution_release değişkeni, Ansible’ın yönetilen sunucunun dağıtım sürümünü (örneğin, focal, jammy) otomatik olarak algılamasını sağlar, bu da playbook’u farklı Ubuntu sürümleri için daha esnek hale getirir. update_cache: yes burada da kullanılarak yeni depo eklendikten sonra paket listesinin güncellenmesi sağlanır.
- name: Docker stabil deposunu ekle
ansible.builtin.apt_repository:
repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable
state: present
update_cache: yes
Docker CE Kurulumu ve Kullanıcıyı Docker Grubuna Ekleme
Artık Docker deposu eklendiğine göre, Docker CE (Community Edition), Docker CLI (komut satırı arayüzü) ve containerd.io (konteyner çalışma zamanı) paketlerini kurabiliriz. Bu üç paket, Docker’ın tam işlevselliği için gereklidir.
- name: Docker CE, Docker CLI ve containerd.io paketlerini kur
ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- docker-ce
- docker-ce-cli
- containerd.io
Kurulumdan sonra Docker servisini başlatıyor ve sistem başlangıcında otomatik olarak başlamasını sağlıyoruz. Bu, sunucu yeniden başlatıldığında Docker’ın çalışır durumda olmasını garanti eder.
- name: Docker servisini başlat ve başlangıçta etkinleştir
ansible.builtin.systemd:
name: docker
state: started
enabled: yes
Varsayılan olarak, Docker komutlarını çalıştırmak için sudo kullanmanız gerekir. Ancak, mevcut kullanıcıyı docker grubuna ekleyerek bu kısıtlamayı kaldırabiliriz. Bu, kullanıcının sudo olmadan Docker komutlarını çalıştırmasına olanak tanır. ansible_user değişkeni, playbook’u çalıştıran kullanıcının adını otomatik olarak alır. append: yes ile kullanıcının mevcut gruplarına ekleme yapılır. Bu değişikliğin etkili olması için kullanıcının oturumu kapatıp açması veya sistemin yeniden başlatılması gerekebilir. Bu nedenle, isteğe bağlı olarak bir yeniden başlatma görevi ekledik, ancak üretim ortamlarında genellikle manuel oturum açma/kapama tercih edilir.
- name: Mevcut kullanıcıyı docker grubuna ekle
ansible.builtin.user:
name: "{{ ansible_user }}"
groups: docker
append: yes
when: ansible_user != 'root' # Eğer root kullanıcısı değilse ekle
- name: Kullanıcı grubu değişikliğini uygulamak için sistemi yeniden başlat (isteğe bağlı)
ansible.builtin.reboot:
when: ansible_user != 'root' # Sadece root olmayan kullanıcılar için gerekli olabilir
Son olarak, Docker kurulumunun başarılı olduğunu doğrulamak için basit bir docker run hello-world komutu çalıştırıyoruz. Bu komut, küçük bir test konteynerini indirir ve çalıştırır, Docker kurulumunun düzgün çalıştığını teyit eder. Çıktıyı debug modülü ile konsola yazdırarak doğrulama adımını görselleştiriyoruz.
- name: Docker kurulumunu doğrula (hello-world çalıştır)
ansible.builtin.command: docker run hello-world
register: docker_hello_world_output
changed_when: false # Bu komut sistemi değiştirmez
- name: Docker hello-world çıktısını göster
ans