Mijn eerste nummer sinds lange tijd

Door armageddon_2k1 op donderdag 02 april 2015 21:11 - Reacties (16)
Categorie: Muziek, Views: 1.472

Ik heb een jaar of 7 in een nu-metal / rock bandje gezet, maar zoals het altijd gaat moet je op gegeven moment ook werken, verhuizen, trouwen (en later kinderen krijgen) en dan heb je niet zoveel tijd meer om 2x per week met een paar gasten in een muf hok te zitten jammen, stonen en algeheel chillen (good times).

Nu ben ik pas 2 jaar gestopt met de band maar het viel me op hoeveel moeite het me kosten om toch een beetje muziek te maken thuis. Laatst toch maar een mooi set monitors gekocht, de zolder opgeknapt, Cubase 8 Pro gekocht en weer aan de slag gegaan.

Without much further ado, het volgende subtiele en gevoelige chanson:



Laat me weten wat je ervan vind :) Ik ben nog op zoek naar een zanger.

Deploying Python apps with Fabric

Door armageddon_2k1 op zondag 15 februari 2015 15:22 - Reacties (0)
Categorie: Dev, Views: 1.662

Sometimes I have a web-site / web-app idea and I start coding a simple setup on my development computer, but eventually I have to deploy it to a web server. Normally I would do this manually and this would comprise of the following steps:
  • Register a hostname
  • Create a VPS somewhere (Digitalocean.com most of the time)
  • SSH into the VPS
  • Install dependencies (Apache2/Nginx, Python, etc…)
  • Pull my app from a VCS somewhere
  • Set the correct privileges
  • Find out, again, how to deploy a WSGI server
  • Profit.
After some coding I want to update it again and I have to do the following:
  • SSH into the VPS
  • Update my app from the VCS
  • Update the dependencies
  • Refresh web server
Especially the initial deployment always takes some time, because I always forget how the privileges should be, what WSGI container I should use, which web-server I will use etc. etc.

Recently I read about the excellent Python package called Fabric, which has a pure SSH implementation in Python and allows you to do all the SSH stuff from within a Python script. I would strongly suggest you to read the introduction of Fabric yourself to understand what is possible. (link)

The focus of this blog entry is the outline of the way I used Fabric to streamline my app deployment.

Setting up Fabric

I usually use a standard setup to organise my Fabfiles by using the modularity of Fabric. In the root of my application folder I have the
fabfile.py
which looks as simple as:

Python:
1
2
3
from deployment.fabric.general import *

env.hosts = ['%s@%s' % (config.ssh_user, config.ssh_host)]


As you can clearly see I put my custom complete fabfile definition in a different module deployment.fabric.general.

[app-root]
  app.py
  fabfile.py
  application
  |-application files / templates / etc
  deployment
  |-__init__.py
  |-configuration.py
  |-fabric
    |-__init__.py
    |-deploy.py
    |-general.py
    |-provision.py
    |-python.py
    |-server.py
  |-templates
    |-app.py.template
    |-app.wsgi.template
    |-vhost.conf.template


By organising it in this way I get a very clean output from the Fabric commandline, since all my commands, except general are bundles in modules and are therefore prefixed:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ fab --list

Available commands:

    check
    deploy
    destroy
    init
    provision
    provision.apache2
    provision.aptitude
    provision.full
    provision.python
    python.app
    python.deps
    python.virtualenv
    python.wsgi
    server.a2dissite
    server.a2ensite
    server.useradd
    server.userdel
    server.vhost



If you look at the deployment.fabric.general.py file the contents look something like this:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from fabric.api import *

import deployment.configuration as config
import deployment.fabric.provision as provision
import deployment.fabric.server as server
import deployment.fabric.python as python
import deployment.fabric.deploy as deploy


@task
def check():
    sudo('uname -a')


@task
def init():
    server.useradd()
    python.virtualenv()
    python.deps()
    python.app()
    python.wsgi()
    server.vhost()
    server.a2ensite()
    server.chown(user=config.app_name, path=config.app_home, recursive=True)

@task(name='deploy')
def deploy_task():
    python.deps()
    deploy.git_pull()

@task
def destroy():
    server.a2dissite(remove=True)
    server.userdel()



Using Fabric

So imagine I have a VPS running at 123.456.78.910. I only have to set the IP-address and a sudo user in configuration.py and I run the following command on my local machine:


code:
1
2
3
4
5
6
$ fab check

[root@123.456.78.910] Executing task 'check'
[root@123.456.78.910] sudo: uname -a
[root@123.456.78.910] Login password for 'root': 
[root@123.456.78.910] out: Linux www.example.com 3.13.0-43-generic #72-Ubuntu SMP Mon Dec 8 19:35:06 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux



and now I know everything is working. To test my deployment I do the following:


code:
1
$ fab provision init


and after a while all my dependencies (Python2.7, Pip, Virtualenv) are fulfilled, a user is added and a basic WSGI app-container is set up (defined in deployment\templates\app.py.template, deployment\templates\app.wsgi.template), a virtual host (defined in deployment\templates\vhost.conf.template and I can check if it works by going to the browser to http://www.example.com. I will see a placeholder website indicating that everything works.

After some actual coding on my app I can then deploy it like follows:

code:
1
$ fab deploy



and my Fabric file takes care of everything:
  • pulling my source code from Git
  • updating my Python dependencies
  • performing touch app.wsgi to trigger a reload of Apache.
If I have updated my app I run fab deploy again and everything is updated within a few seconds.

Closing off

This blog entry isn’t some in-depth step-by-step tutorial of constructing a Fabfile, but more of an overview of how I used it. I hope this wetted your appetite, because I fell in love with using Fabric.

If people are interested I am willing to make a blog series of how I made the Fabfile step by step :-)

Webdevelopment workflow met Vagrant en Chef

Door armageddon_2k1 op vrijdag 11 januari 2013 13:27 - Reacties (9)
Categorie: Dev, Views: 3.907

Welkom op de allereerste post van mijn Tweakblog. Een paar maanden heb ik deze maar eens geactiveerd maar ik ben er eigenlijk nog niet aan toegekomen om wat te schrijven. Naar aanleiding van wat post en een ander Tweakblog over workflow met een VM besloot ik mijn ervaringen ook maar eens op te schrijven omdat daar specifiek naar gevraagd werd :).

Ontwikkelen binnen een VM


Ik ga hier niet uitgebreid in op de voordelen van het ontwikkelen binnen een Virtual Machine, want daar is genoeg over te vinden op het web. Er zitten nadelen aan vast, maar voor mij wegen die niet op tegen de enorme voordelen. Het biedt mij een enorme flexibiliteit en 'schoonheid' van mijn systeem, alhoewel ik me voor kan stellen dat als je niet, zoals ik, louter met PHP en Python werkt voor web-applicaties en je meer aan de .NET kant doet het verhaal wellicht anders is.

Mijn insteek is, net als in veel programmeertalen het geval is, seperation of concerns. Mijn computer is geen webserver en geen database server. Het is wél een ontwikkelbak waar op getypt kan worden. Mijn server is geen ontwikkelbak waar tools opstaan zoals PHPStorm en SublimeText, maar wél Apache2 en PHP5. Verder niks.

Idealiter wil ik dus een VM hebben waar alles op draait en ik zonder al te veel gedoe mijn code die ik aan het tikken ben live kan zetten op de server en het daar kan zien.

Vagrant


Laat dit nu net zijn waar Vagrant goed in is! En dan knippen ze de laatste stap eruit, want het live zetten hoeft niet eens. Ik ontwikkel direct op de VM, mét mijn eigen tools op mijn eigen bak.

Ik ga hier geen tutorial neerplempen van Vagrant, want dat kunnen die mannen en vrouwen prima zelf. Ik zou maar eens kijken op: www.vagrantup.com: Getting Started With Vagrant. Die tutorial kost je 10 minuten en dan snap je precies wat ik bedoel.

Web-app development met Vagrant


Op naar de hoofdmoot van mijn verhaal. Ik ga een basis Apache2 server met PHP hier maken met de volgende eisen.
  • Debian-like server 32 bit, hetzelfde als op mijn VPS draait
  • Apache2
  • PHP5.3.8 of hoger
  • php_apc (voor het cachen van php-code en data)
  • XDebug (voor het debuggen)
Al met al geen grote lijst en snel op te zetten met Vagrant. Let wel, Vagrant i.c.m. Chef is tot heel veel in staat en kan je hele specifieke configuraties opzetten.
Ik ontwikkel alles op OSX, dus alle commandos zijn terminal commands binnen de terminal van OSX. Alle commandos zijn vanuit een directory ergens in mijn home-dir (~/Vagrant/php-dev), maar dat mag je natuurlijk helemaal zelf kiezen.

Vagrant base-box installeren

Het project is gestart en nu ga ik een vagrant instantie toevoegen aan dit project. Het gaat een VM zijn gebaseerd op Ubuntu Precise 32 welke al in base-box vorm bestaat gemaakt door de lui van Vagrant zelf. Andere base-boxes kan je hier en hier vinden. Informatie over het maken van een eigen base box staat hier.

Tijd om de base-box te downloaden, een VM te maken in de map vagrant en hem te starten.
$ mkdir vagrant
$ cd vagrant
$ vagrant box add precise32 http://files.vagrantup.com/precise32.box
[vagrant] Downloading with Vagrant::Downloaders::HTTP...
[vagrant] Downloading box: http://files.vagrantup.com/precise32.box
[vagrant] Extracting box...
[vagrant] Verifying box...
[vagrant] Cleaning up downloaded box...

$ vagrant init precise32
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Zoals je ziet heb ik de base box gedownload van een webserver en hem lokaal precise32 genoemd. Daarna heb ik met het init command een nieuwe Vagrant box aangemaakt gebaseerd op de precise32 base box.

De VM staat klaar! Tijd om hem te runnen.
$ vagrant up
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant

Zoals je merkt is ie eerst bezig met het kopieren van de precise32 base box en daarna start ie! De SSH port 22 op het VM systeem wordt doorgelust naar onze eigen 2222 port number, dus we kunnen gewoon SSH'en naar 127.0.0.1:2222 en dan zitten we in het Vagrant systeem.

Gelukkig heeft Vagrant ook gewoon het ssh commando zodat we even kunnen rondneuzen op het systeem.
$ vagrant ssh
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)
vagrant@precise32:~$ ls /
bin   dev  home        lib         media  opt   root  sbin     srv  tmp  vagrant  vmlinuz
boot  etc  initrd.img  lost+found  mnt    proc  run   selinux  sys  usr  var
vagrant@precise32:~$ ls /vagrant
Vagrantfile
vagrant@precise32:~$ logout

Zoals je ziet is er een root folder /vagrant bijgekomen welke letterlijk naar onze Vagrant folder op onze host verwijst. Zoals je ziet staat daar de Vagrantfile waar het hele systeem in gedefinieerd wordt. Door zo folders te mounten naar ons host systeem kunnen we makkelijk een web-applicatie op ons host systeem houden en hem gewoon draaien binnen het VM als web-app.

Provisioning Vagrant met Chef Solo

Chef Solo is een onderdeel van Opscode Chef waar je hele installaties mee kan automatiseren, wat ook wel provisioning genoemd wordt. Meer over provisioning van Vagrant kan je hier lezen.

Laten we de Vagrantfile aanpassen naar een basis waarmee we kunnen gaan provisionen met Chef:

ruby:
1
2
3
4
5
6
7
8
9
10
11
12
Vagrant::Config.run do |config|
  config.vm.box = "precise32"

  # ik zorg voor 2 virtuele netwerkkaarten, zodat ik onderling VM's ook makkelijk met elkaar kan laten communiceren (denk aan PHP -> MySQL)
  config.vm.network :hostonly, "33.33.33.10" 
  config.vm.network :bridged
  config.vm.forward_port 80, 8080 # ik forward port 80 op de guest naar 8080 op de host
 
  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "cookbooks"
  end
end


Op het moment is er nog geen enkel Chef recipe ingeladen maar denkt ie z'n cookbooks, met daarin recipes, in de cookbook folder relatief t.o.v. de Vagrantfile te vinden, dus laten we die maken.
$ mkdir cookbooks

Nu is het tijd om de cookbooks op te halen die Opscode al gemaakt heeft of elders online beschikbaar zijn. In ons geval gaat het om apt, apache2, php cookbooks. De apt-cookbook gebruik ik omdat dan de aptitude repositories elke keer geupdate worden en voor het toevoegen van eventuele andere repositories. Voor meer cookbooks raadt ik je aan te kijken op de Opscode Github. Daar kan je van alle cookbooks alle broodnodige informatie vinden.

Tijd om de cookbooks binnen te halen met Git:
$ git clone git://github.com/opscode-cookbooks/apt.git cookbooks/apt
$ git clone git://github.com/opscode-cookbooks/apache2.git cookbooks/apache2
$ git clone git://github.com/opscode-cookbooks/php.git cookbooks/php


en om ze te activeren in de Vagrantfile:

ruby:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Vagrant::Config.run do |config|
  config.vm.box = "precise32"
  config.vm.network :hostonly, "33.33.33.10"
  config.vm.network :bridged
  config.vm.forward_port 80, 8080
 
  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "cookbooks"
    chef.add_recipe("apt")
    chef.add_recipe("apache2")
    chef.add_recipe("apache2::mod_php5")
    chef.add_recipe("php")    
  end
end


Nu moeten we Vagrant box opnieuw opstarten de configuratie te harladen en om Chef z'n gang te laten gaan:
$ vagrant reload
[default] Attempting graceful shutdown of VM...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
--- knip ---
$ vagrant ssh
vagrant@precise32:~$ apachectl -v
Server version: Apache/2.2.22 (Ubuntu)
Server built:   Nov  8 2012 21:37:45
vagrant@precise32:~$ php -v
PHP 5.3.10-1ubuntu3.4 with Suhosin-Patch (cli) (built: Sep 12 2012 19:00:43) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
vagrant@precise32:~$ logout


Voila, Apache2 en PHP5.3.10 staan erop! Momenteel draait er nog geen enkele website. Tijd om een website toe te voegen.

Web applicatie toevoegen

Als je bekend bent met Apache2 dan weet je dat je een conf bestand kan maken met de Virtualhost gegevens en die vervolgens in de sites-available directory kan activeren. Gelukkig kan dit ook allemaal met Chef. We maken een eigen recipe welke onze Virtualhost configureert en bijkans ook APC en XDebug installeert.

Begin met het maken een eigen cookbook met bijbehorende mappenstructuur en Ruby files (voor meer informatie over eigen recipes moet je de Chef documentatie lezen):
$ mkdir cookbooks/custom_app
$ mkdir cookbooks/custom_app/attributes
$ mkdir cookbooks/custom_app/recipes
$ mkdir cookbooks/custom_app/templates
$ mkdir cookbooks/custom_app/templates/default
$ touch cookbooks/custom_app/recipes/default.rb
$ touch cookbooks/custom_app/attributes/default.rb
$ touch cookbooks/custom_app/templates/default/custom_app.conf.erb

De laatste is een Ruby template waarmee we de VirtualHost conf maken.

En de inhoudt van de bestanden:
cookbooks/custom_app/attributes/default.rb

ruby:
1
2
default['custom_app']['server_name'] = 'web-app.dev'
default['custom_app']['docroot']      = '/web-app'


cookbooks/custom_app/templates/default/custom_app.conf.erb

ruby:
1
2
3
4
5
6
7
8
9
10
11
<VirtualHost *:80>
  ServerName <%= @params[:server_name] %>
  DocumentRoot <%= @params[:docroot] %>

  <Directory <%= @params[:docroot] %>>
    Options FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
  </Directory>
</VirtualHost>


Als laatste hebben we de daadwerkelijke recipe nodig:
cookbooks/custom_app/recipes/default.rb

ruby:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
app_name = 'custom_app'
app_config = node[app_name]

# install APC
package "php-apc" do
    action :install
end

# install XDebug
package "php5-xdebug" do
    action :install
end

# set up the Apache virtual host 
web_app app_name do 
  server_name app_config['server_name']
  docroot app_config['docroot']
  template "custom_app.conf.erb" 
end

Zoals je ziet halen we in het begin een app_config op (welke naar de attributes verwijst of in onze Vagrantfile te definieren is), dan worden APC en XDebug middels aptitude geinstalleerd en daarna renderen we vhost.conf met die attributes.

Zoals je ziet in attributes/default.rb is de doc-root van onze website op /web-app in ons guest VM. Laten we die even toevoegen en mappen naar een map op onze host. Ik maak op onze host een map aan genaamd web-app welke 1 niveau hoger ligt dan de vagrant map. Dan houd ik alles netjes gescheiden:
$ mkdir ../web-app
$ ls ../
vagrant	web-app


En om een mapping toe te voegen passen we onze Vagrantfile als volgt aan:

ruby:
1
2
3
4
5
--- knip ---
config.vm.network :bridged
config.vm.forward_port 80, 8080
config.vm.share_folder "web-app", "/web-app", "../web-app"  # voeg deze regel toe.
--- knip ---

Hier voegen we een nieuwe mapping, genaamd web-app toe welke /web-app op onze guest mount op ../web-app op onze host.

Nu moeten we alleen onze web-app nog via Chef toevoegen, door hem in onze Chef lijst in de Vagrantfile te zetten:

ruby:
1
2
3
4
5
6
7
8
9
--- knip ---
config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "cookbooks"
    chef.add_recipe("apt")
    chef.add_recipe("apache2")
    chef.add_recipe("apache2::mod_php5")
    chef.add_recipe("php")
    chef.add_recipe("custom_app") # voeg hier onze eigen recipe toe
  end


En tijd om een documentje in de web-app folder te zetten en Vagrant te starten:
$ echo "<?php phpinfo(); ?>" > ../web-app/index.php
$ vagrant reload


Als het goed is draait onze web-applicatie nu op een Apache2 server binnen een Ubuntu distributie op onze VM maar is ie te benaderen vanuit localhost:8080. Even checken of het zo is:
vagrant-vm-working
Jawel! Het werkt allemaal, en zoals je kan zien zijn XDebug en APC ook aanwezig.

Gebruik van de box voor verder gebruik

Het mooie is dat deze VM nu helemaal gedefinieerd wordt door de Vragrantfile en de bijbehorende cookbooks. Het enige wat ik hoef te doen om deze VM te hergebruiken is de map vagrant kopieren en dan kan ik hem voor andere web-applicaties gebruiken. Voordat je zo'n kopieeractie doet is het wel handig alle gegenereerde data van vagrant up, weg te halen zodat je schoon kan beginnen.
$ vagrant destroy


Zelf heb ik een vergelijkbare box als Git repository ergens staan en die clone ik dan in mijn projecten. In mijn .gitignore van het project staat dan simpelweg /vagrant zodat de VM netjes gescheiden staat van mijn source.

Het aanpassen van attributes is ook geen enkel probleem en kan vanuit onze Vagrantfile. Hiervoor verwijs ik je naar de Chef documentatie. In ons geval kan een je de custom_app attributen als volgt aanpassen in de Vagrantfile:

ruby:
1
2
3
4
5
6
  chef.json = {
      "custom_app" => {
        "server_name" => 'symfony2-app.dev',
        "docroot"     => '/web-app/web'
      }
    }

Zoals je ziet kan dat voor krachtige flexibiliteit zorgen.

Afsluiting


Dit is een hele korte introductie van Chef en Vagrant, maar hopelijk laat het z'n kracht zien. Ik raadt je zeker aan de volgende sites te bezoeken voor meer informatie:
http://www.vagrantup.com
http://wiki.opscode.com/display/chef/Home
http://www.jasongrimes.or...f-vagrant-and-ec2-3-of-3/
https://github.com/opscode-cookbooks
https://github.com/simshaun/symfony-vagrant

Ik vind Vagrant best een innovatieve manier om mijn PHP-applicaties te ontwikkelen, zonder dat het mijn host bevuilt en hopelijk heb ik dat duidelijk kunnen maken :)

Mochten er op- of aanmerkingen zijn, schroom dan niet, want aangezien dit mijn eerste post is zullen er wel wat dingen onduidelijk danwel fout ingezet zijn.