Vagrant
Not: Vagrant VM kullanıcısı
vagrant
, parolasıvagrant
'tır.
Vagrant ne işe yarıyor
Vagrant bir sanal makine yöneticisi. Bilgisayarınızdaki sanal makinelerin oluşturulmasından kurulumuna, çalıştırılmasına ve izlenmesine yönelik kolaylıklar sunuyor. Açık kaynak ve cross-platform (MacOS, Windows, Linux) bir yazılım. Şu anda VMWare, VirtualBox ve AWS (Amazon Web Services) üzerinden oluşturulan VM'leri yönetebiliyorsunuz. Bu ne demek oluyor? Aynı Vagrant konfigürasyonu üzerinden farklı VM'leri çok rahat kullanabiliyorsunuz.
Peki bu bizim gerçek hayatta ne işimize yarayacak? Örnekler ne olabilir?
Öncelikle development kalitesini arttıran bir yönü var. Şirkete ilk başladığınızda projeyi kendi bilgisayarınızda ayağa kaldırmak için ne kadar uğraştınızı hatırlıyor musunuz?
Ya da tüm bu işlemleri staging, test ve production ortamlarına da yapmak yaşlanmanıza neden olabilir. Diyelim ki deployment sürecinize yeni bir ortam ekliyorsunuz (mesela UAT için) ve yeni bir makine, yeni kurulum yapmanız gerekiyor. Uygulamanızın tüm bağımlılıklarının o makineye kurulması gerekiyor. Bu projenizin büyüklüğüne göre bazen bir haftayı bulan süreçlere uzayabilir.
Ancak vagrant'ın belki de en yararlı olduğu konu production ortamındaki hatalarının development'da yakalanabilmesini sağlaması. "Bende çalışıyor" - "Kendi ortamımda reproduce edemedim" gibi iğrenç söylemler tarih oluyor :)
Gereksinimler
Vagrant provider olarak kullanacağı bir VM yöneticisine ihtiyaç duyuyor. Birçok provider desteklendiğini daha önceden söylemiştik. Bu yazı için varsayılan olarak sunulan ve yine açık kaynak ücretsiz VM VirtualBox'ı kullandım. Virtualbox'ı indirmek için: tıklayın.
Vagrant kurulumu
- Bir adet vagrant http://www.vagrantup.com/downloads
Box konumunu ayarlamak
Not: Bu anlatım Mac OS X veya Linux için geçerlidir
Vagrant'ın indirdiği box dosyaları default yeri:
~/.vagrant.d/boxes
Çok yer kaplayabileceğinden ötürü bu folder'ı değiştirmek isterseniz
favori text editörünüzde .bash_profile
dosyanızı açın: (nano yerine vi de kullanabilirsiniz)
1sudo nano ~/.bash_profile
Şu satırı ekleyin:
export VAGRANT_HOME="/<BURAYA ISTEDIGIN FOLDERI YAZ>"
Artık indirilip oluşturulan VM dosyaları istediğimiz bir folder altında olacak.
İşletim sistemi kurmak
Harshi Corp.'un Atlas'ı üzerinde birçok Linux seçeneği mevcut tabii ancak Ubuntu aşina olduğum bir dağıtım ve LTE sürümü olduğundan seçiyorum: https://atlas.hashicorp.com/ubuntu/boxes/trusty64
Dökümantasyonunda söylediği şekilde kuruyorum.
1vagrant init ubuntu/trusty64
2vagrant up
init komutu bulunduğumuz yerde bir VagrantFile
yaratacaktır. Buradaki bilgilere göre vagrant up
dediğimizde kurulum, bu ayarlar üzerinden gerçekleşecek.
up komutuyla birlikte ilgili işletim sistemi dosyası indirilir ve o sanal makine çalıştırılır.
vagrant --help
ile yararlı birçok komutu görebilirsiniz.
Box'a bağlanmak
öncelikle kurulu box'ları görmek için: vagrant box list
diyoruz.
1ubuntu/trusty64 (virtualbox, 20151020.0.0)
Şimdi de bağlanmak için vagrant ssh
diyoruz, bu bizi VagrantFile'daki sisteme bağlayacak.
1vagrant@vagrant-ubuntu-trusty-64:~$
Artık terminal bağlantım değişti, bu ssh ile bağlanabildiğimi gösteriyor.
Gerekliliklerin kurulması
Aşağıdaki gereklilikler tamamen benim bu örnekte anlattığım node.js uygulaması ve onun bağımlılıklarını içerir.
Uygulamamızı çalıştırmak için gerekli araçları kuracağız.
1sudo apt-get -y install git build-essential
2curl --silent --location https://deb.nodesource.com/setup_4.x | sudo bash -
3sudo apt-get install -y nodejs redis-server
4sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
5echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.0.list
6sudo apt-get update
7sudo apt-get install -y mongodb-org
Redis ayarlarımızı yapalım: (vi yerine nano da kullanabilirsiniz) Uygulamamızın kullandığı konfigürasyon redis.sh scriptinde bu path kullanılıyor. ~~~ sudo vi /etc/redis/redis.conf ~~~
notify-keyspace-events
geçen satırı şu şekilde değiştirelim:
1notify-keyspace-events "Kgs"
Ardından redis'i yeniden başlatalım:
1sudo service redis-server restart
Şimdi de uygulamayı indirip çalıştıralım:
1git clone https://github.com/dhalsim/chatcat.git
2cd chatcat
3git checkout dort
4npm install
5sudo npm install grunt-cli -g
Bu komutların hepsini bir dosyaya kaydediyoruz: provision.sh. Ardınan VagrantFile
'ı açıp düzenleme yapıyoruz. Şu şekile getirin:
1 -*- mode: ruby -*-
2
3Vagrant.configure(2) do |config|
4 config.vm.box = "ubuntu/trusty64"
5 config.vm.network "forwarded_port", guest: 3000, host: 8080
6 config.vm.provision :shell, path: "provision.sh"
7end
ssh'tan exit
ile çıkıyoruz:
1vagrant reload --provision
Böylece vagrant, VM'i kapatacak, tekrar açacak ve verdiğimiz provision.sh
dosyasından kurulum yapacak
Vagrant senkronizasyon
Vagrant VM'ler üzerinde geliştirme yapmak özellikle grafik arabirimi olmadığından çok zor olabilir. terminal programlarıyla çok içli dışlı değilseniz, host makinenizdeki uygulamalarınızı kullanmak istiyorsanız, vagrant VM guest makineniz ile host makineniz arasında ortak senkronize dosyaları kullanabilirsiniz. Data transferi açısından da faydalıdır.
Burada Mac OSX host makinesi ve VirtualBox ubuntu guest makinesi arasındaki kullanımı anlatacağım. Sizde farklı bir kombinasyon varsa ve bunlar işe yaramazsa ayrıntılı bilgi vagrant dökümantasyonu'nda.
Şimdi VagrantFile
'ı değiştirelim:
1Vagrant.configure(2) do |config|
2 config.vm.box = "ubuntu/trusty64"
3 config.vm.network "forwarded_port", guest: 3000, host: 8080
4 config.vm.provision :shell, path: "provision.sh"
5 config.vm.synced_folder "~/Projects/chatcat", "/home/vagrant/chatcat"
6end
- config.vm.synced_folder komutunu ekledik
- ilk parametredeki path, host makinedeki
- ikinci parametredeki path, guest makinesindeki yeri belirtiyor
1vagrant reload
2vagrant ssh
ile kontrol ediyoruz. Artık host makinemizde istediğimiz editör/IDE ile bir dosya değiştirdiğimizde otomatik olarak o dosya Vagrant tarafından guest makineye senkron edilecek.
Port Forwarding
Port forwarding, vagrant box'da çalışan bir portu benim bilgisayarımın başka bir portuna yönlendirmek/bağlamak anlamına geliyor.
1config.vm.network "forwarded_port", guest: 3000, host: 3000
Artık VM'in 3000 portu, bizim bilgisayarımızın 3000 portuna yönlenmekte.
Kendi bilgisayarınızda http://localhost:3000'den uygulamamızı deneyebiliriz. Afiyet olsun :)
Private Network
Vagrant sanal makinelerinizin bir private network altında birbirleriyle haberleşebilmelerini sağlayabilirsiniz. Bunun için yapmanız gereken:
1config.vm.network "private_network", ip: "192.168.1.20"
Bu yöntemle port forwarding yapmamıza gerek kalmıyor. O satırı silip localhost yerine http://192.168.1.20:3000 üzerinden de uygulamayı çalıştırabilirsiniz.
Guest OS (konuk işletim sistemi) için bir IP tanımlamak. Ayrıca VM'inizin Host OS (yönetici işletim sistemi) DNS'ini veya başka bir DNS server'ını kullanmasını sağlayabilirsiniz.
VirtualBox için bu şu komutla yapılabiliyor: (VM'in kapalı olduğundan emin olun: vagrant halt
)
1VBoxManage list vms --> VM listesinden ismi alıp aşağıya yazın
2VBoxManage modifyvm "VM İSMİNİZİ BURAYA YAZIN" --natdnshostresolver1 on
Eğer sürekli IP hatırlamakla uğraşmak istemiyorsanız hosts dosyasına anlamlı isimler verebilirsiniz. Mac OSX için dosyayı değiştirelim (vi yerine nano da kullanabilirsiniz)
1sudo vi /private/etc/hosts
En alt satıra 192.168.1.20 nodeapp.com
ekleyip kaydedin. Daha sonra http://nodeapp.com:3000 şeklinde o vagrant üzerindeki node.js uygulamamıza erişebileceğiz. Üstelik eğer diğer VM'lerde de VBoxManage ile yaptığımızı yaparsak, aynı network ve DNS ayarları üzerinden onlar da erişebilirler. Bundan sonraki anlatımlarda nodeapp.com üzerinden gideceğim.
Bu yaptığımız değişiklik facebook login işlemlerinde ve socket işlemlerinde probleme yol açacak. Facebook application ayarlarından localhost geçen yerleri nodeapp.com ile değiştirmemiz gerekiyor. Bunlar config/commons.js'te socket_host değişkeli ve test.json'da değiştireceğimiz callbackURL değişkenidir. Yapılması gerekenler:
- http://developers.facebook.com üzerinden uygulamamızın ayarlarını değiştirmeliyiz. Benim önerim Test Apps üzerinden yeni bir test uygulaması yaratıp, Site URL'i http://nodeapp.com:3000/ şeklinde ayarlamanız. Bu durumda test.json'a yeni AppID ve AppSecret değişkenlerini güncellemeyi unutmayın
config/index.js'te daha önceden farketmediğim bir durum var. Onu düzelteceğiz. Normalde yapılması gereken, ortak ayarların ezilmesini sağlamaktır. commons ve environmentConfig yer değiştirecek:
1module.exports = require('src/lib/utils').extend(commons, environmentConfig);
test.json'a commons.json'daki socket_host'u ezebilmek için şunu ekliyoruz:
1... 2"socket_host": "http://nodeapp.com:3000", 3...
Bu en çok VM'leriniz arasında iletişim kurmak istediğinizde -ki bunu isteyeceksiniz- IP'ler yerine FQDN'lerle (nodeapp.com gibi) yapabilmenizi sağlayacak.
Uygulamayı servis olarak çalıştırmak
Şimdiye kadar Vagrant üzerinden node.js uygulamamızı Ubuntu/Linux'a kurulumunu ve çalıştırılmasını anlattım. Şimdi ise uygulamamızın yönetimini ve izlenmesini sağlayacak PM2 ismindeki aracın kullanımını göreceğiz. Üstelik PM2 ile uygulamanın crash olması durumunda yeniden başlatılmasını da sağlayacağız. Ayrınca herhangi bir VM restart durumunda da uygulamanın servis olarak otomatik çalışmasını sağlayacağız.
Uygulamamızı VM'i başlattığımızda otomatik başlaması için ayarlamamız gerekiyor. Bu aynı zamanda VM'in yeniden başlamalarında da gerekli olacaktır.
PM2'yi kuruyoruz:
1sudo npm install -g pm2
PM2'nun karışık komutlarında bize bir nebze olsun yardımcı olacak komut tamamlama için:
1pm2 completion install
Bulunduğunuz terminalde işe yaraması için gerekli komut, olmuyorsa terminal penceresini/tabını kapatıp açabilirsiniz de:
1source ~/.bashrc
NOT: pm2 aslında bizim işimize yarayacak birçok özelliğe sahip ancak bu yazının konusunu aştığından buna başka bir yazıda değineceğim. Siz isterseniz araştırabilirsiniz, faydalıdır. http://pm2.keymetrics.io/docs/usage/pm2-doc-single-page/
Servis ayarlarına girmeden önce grunt tarafında değişiklikler yapacağız. Şimdiye kadar uygulamamız dev modunda çalışıyordu. VM için test modunu kullanmaya karar verdim. Siz kafanıza göre ayarlayabilirsiniz. Bana göre servis olarak çalıştırırken de redis, mongo gibi kullanılan tüm program ve ayarlar en rahat yine grunt ile ayarlanabiliyor, ancak bu sefer development için kullandığımız watch, nodemon gibi araçlar yerine pm2 kullanacağız. Uzatmadan yapmamız gerekenlere geçersek:
Spoiler: Programın vagrant için hazır halini
git checkout bes
diyerek kullanabilirsiniz. O durumda aşağıda yapılan değişikliklerden bazılarına gerek kalmayacak.
dev.json
dosyasının içeriğinitest.json
dosyasına kopyalayın. Kolaylık olması açısından VM üzerinde de cloud yerine aynı makinedeki servis olarak çalışan redis, mongo kullanılacak.service --status-all
ile redis, mongo servislerinin çalıştığından emin olun- console'dan
NODE_ENV=test pm2 start app.js
ile test edin. - çalışıyorsa
pm2 kill
ile kapatın startup.sh
adında yeni bir dosya ekliyoruz. Bu dosya bizim oluşturacağımız servis'in çalışmasını, durdurulmasını vs. sağlayacak. Kontrol edilmesi gereken yerler NAME, PM2, USER, APP_HOME gibi değişkenler. Mesela user'ınwhoami
ile kontrolünü yapabilirsiniz.which pm2
diyerek pm2'nun asıl yerini öğrenebilirsiniz.1#!/bin/bash 2 chkconfig: 2345 98 02 3# 4 description: our chatcat node app startup script 5 processname: chatcat 6# 7## BEGIN INIT INFO 8 Provides: 9 Required-Start: $local_fs $remote_fs 10 Required-Stop: $local_fs $remote_fs 11 Should-Start: $network 12 Should-Stop: $network 13 Default-Start: 2 3 4 5 14 Default-Stop: 0 1 6 15 Short-Description: chatcat 16 Description: chatcat node app is started 17## END INIT INFO 18 19NAME=chatcat 20PM2=/usr/bin/pm2 21USER=vagrant 22APP_HOME="/home/vagrant/chatcat" 23 24export NODE_ENV="test" 25 26get_user_shell() { 27 local shell=$(getent passwd ${1:-`whoami`} | cut -d: -f7 | sed -e 's/[[:space:]]*$//') 28 29 if [[ $shell == *"/sbin/nologin" ]] || [[ $shell == "/bin/false" ]] || [[ -z "$shell" ]]; 30 then 31 shell="/bin/bash" 32 fi 33 34 echo "$shell" 35} 36 37super() { 38 local shell=$(get_user_shell $USER) 39 su - $USER -s $shell -c "NODE_ENV=$NODE_ENV $*" 40} 41 42start() { 43 echo "Starting $NAME" 44 super $PM2 start $APP_HOME/app.js 45} 46 47stop() { 48 super $PM2 dump 49 super $PM2 delete all 50 super $PM2 kill 51} 52 53restart() { 54 echo "Restarting $NAME" 55 stop 56 start 57} 58 59reload() { 60 echo "Reloading $NAME" 61 super $PM2 reload all 62} 63 64status() { 65 echo "Status for $NAME:" 66 super $PM2 list 67 RETVAL=$? 68} 69 70case "$1" in 71 start) 72 start 73 ;; 74 stop) 75 stop 76 ;; 77 status) 78 status 79 ;; 80 restart) 81 restart 82 ;; 83 reload) 84 reload 85 ;; 86 force-reload) 87 reload 88 ;; 89 *) 90 echo "Usage: {start|stop|status|restart|reload|force-reload}" 91 exit 1 92 ;; 93esac 94exit $RETVAL
sudo cp startup.sh /etc/init.d/nodeapp
ile dosyayı servislerin çalıştırıldığı path'e kopyalayınsudo chmod a+x /etc/init.d/nodeapp
ile dosyaya çalıştırma izni verinsudo service nodeapp start
ile servisi başlatın. Denemek içinsudo /etc/init.d/nodeapp start
da diyebilirsiniz.pm2 list
ile uygulamanın başlayıp başlamadığına emin olunsudo service nodeapp stop
uygulamayı durdurun.pm2 list
ile çalışan uygulama olmadığına emin olun.ps aux | grep node
ile node.js'in çalışmadığını görün.Her şey OK ise servisi başlangıçta çalışması için şu komutu girelim:
sudo update-rc.d nodeapp defaults
Not: Tüm bunları denerken bir problemle karşılaşırsanız basitten karmaşığa doğru ilerleyin. Önce
startup.sh
çalışıyor mu. Daha sonra da service çalışıyor mu diye bakabilirsiniz.Ayrıca
provision.sh
dosyasında da değişiklik yapmamız gerekiyor:
1...
2git clone https://github.com/dhalsim/chatcat.git
3cd chatcat
4git checkout bes
5npm install
6sudo npm install grunt-cli -g
7sudo npm install -g pm2
8sudo cp startup.sh /etc/init.d/nodeapp
9sudo chmod a+x /etc/init.d/nodeapp
10sudo update-rc.d nodeapp defaults
Şimdilik bu kadar. Vagrant kullanması gerçekten hoş bir ortam sunmuş. Ancak Linux ile çok alakadar olmayan gençlerimiz yabancılık çekiyor olabilir. Linux ile ilgili tonlarca kaynak bulabilirsiniz. Biraz bakmanızda fayda var. Takıldığınız yerlerde yorumlara yazarsanız oradan da yardımcı olmaya çalışırım.
Bir sonraki yazımda uygulamamızı Vagrant üzerinden clustured şekilde nasıl çalıştıracağımızı ve böyle durumunlarda loglama nasıl yönetilir bunun üzerinde duracağım. Loglama açısından çok sağlam bir yazı bizi bekliyor :)