Bloghttp://bscientific.org/blog/feeds/atom/2013-01-30T22:42:43+00:00This content is updated infrequently. The interesting stuff happens in real life.Mezzanine Workflow2013-01-30T22:42:43+00:00Ken Bolton/blog/author/ken/http://bscientific.org/blog/mezzanine-workflow/<p><strong>UPDATE December 8, 2014:</strong> I now believe the `runserver` is an anti-pattern. All development should be on a VM.</p>
<p>This is the basic Mezzanine workflow to get projects completed rapidly. Written in response to a question posted to mezzanine-users, this is a companion to the article on Mezzanine deployment process.</p>
<p>Start with the django runserver and get a site running at http://localhost:8000/. I see a lot of people asking for help with their server who do not have a local version running. Never trust a developer who does everything on production!</p>
<p>Be sure to `pip install django-debug-toolbar`, because it will help you grow your understanding of what Django and Mezzanine are doing "behind the scenes". Of particular interest is the "Templates" tools. It shows the order of the template inheritance as well as the template context, e.g. the value of "page".</p>
<p>Build out your site's information architecture at http://localhost:8000/admin/. Put in your "About Us" page and your forms, etc. Advanced users can use the same type of database they expect to use in production (more postgres, mom, please) and dump the data out for uploading to production.</p>
<p>At this point, you will have what I affectionately call a "functional wireframe" of the site. Everything works, though it probably does not look how you want it to look. This is a good time to begin working on the design. (Why? Designers often – no offense – miss crucial parts of the site. On a recent project, the design had to be redone because they forgot to include a way to login, which was prominent in the functional wireframe.)</p>
<p>The advantage of using bootstrap is that the DOM classes and IDs are consistent across all bootstrap-based sites. Thus, all bootstrap CSS is fairly similar. The form CSS declarations in bootstrap is totally unrelated to the mezzanine.forms app. The best way to get going is to "Customize" your bootstrap at http://twitter.github.com/bootstrap/customize.html.</p>
<p>Now, and only now, would I begin to muck about with the templates. Using the debug toolbar, figure out which template you want to modify and copy it from Mezzanine to your project's spanking-new `templates` directory. Iterate on this until you get through all of the pages of your site.</p>Deploying Mezzanine: Fabric Git Vagrant Joy2013-01-14T04:21:53+00:00Ken Bolton/blog/author/ken/http://bscientific.org/blog/mezzanine-fabric-git-vagrant-joy/<h3><span>Preface</span></h3>
<p>In this demonstration, we will install the python applications `virtualenv`, `virtualenvwrapper`, the excellent open source Mezzanine CMS, and the Django "web framework for perfectionists with deadlines". We will create a basic Mezzanine project populated with sample data, run the Django development server, and access and admin of the site at http://127.0.0.1/.</p>
<p>We will then build a Vagrant virtual machine running Ubuntu 12.04 LTS, Nginx, Gunicorn, Memcached, PostgreSQL, and Supervisor, and deploy the Mezzanine project to it from a git repository using Fabric. Changing the HOSTS variable in the included Fabric settings to your host's name or IP will allow you to build, install, and deploy your site with a single command. </p>
<p>This is a work in progress, hastily written late at night for a friend while waiting for a client's code to deploy. Suggestions for improvement are welcome. YMMV. This article contains topics in advanced web software engineering and is not intended as an introduction to Django, Mezzanine, Python, etc. Matthew Krohn served as a test subject and provided lots of valuable feedback.</p>
<h3>Deploying To Production Must Never Break Production</h3>
<p>Deploying Django web applications can be a struggle. After years, I finally found the sweet spot. <a href="http://mezzanine.jupo.org/">Mezzanine</a>, the CMS built on Django by Stephen McDonald and many awesome contributors, gets it right. A bundled Fabric script, a settings.FABRIC dictionary, your code on a hosted git or mercurial repository, and an Ubuntu box – be it Vagrant, AWS, a hosted VPS, or dedicated hardware – and you can spin up a server like it was nothing. Following, please find my technique for starting and deploying Django projects before a single line of code gets written. These instructions will give you a deployed Ubuntu 12.04 box running PostgreSQL, Nginx, Gunicorn, Supervisord, and Memcached.</p>
<h3>Assumptions</h3>
<p>These instructions will work best on a GNU/Linux or MacOSX. At this writing, VirtualBox is required to run The Vagrant, as is Ruby. In Ubuntu, `sudo apt-get install ruby-dev`. Unless otherwise stated, everything is done on localhost.</p>
<h3>Ingredients</h3>
<p>The links below are to the installation instructions.</p>
<ul>
<li><a href="http://pypi.python.org/pypi/virtualenv">virtualenv</a></li>
<li><a href="http://virtualenvwrapper.readthedocs.org/en/latest/install.html#basic-installation">virtualenvwrapper</a></li>
<li><a href="http://mezzanine.jupo.org/docs/overview.html#installation">Mezzanine</a> (or <a href="http://cartridge.jupo.org/">Cartridge</a>, which is a Mezzanine shop)</li>
<li><a href="http://vagrantup.com/">The Vagrant</a></li>
<li><a href="http://git-scm.com/">Git</a></li>
<li>A host. Instructions below assume a virtualized Ubuntu 12.04 Precise Pangolin 64 bit host managed by The Vagrant.</li>
</ul>
<h3>Virtualenv</h3>
<p>Virtualenv is a way to create isolated python environments for your projects. This becomes exceptionally handy when you have to support Django 1.0 sites on the same development machine as Django 1.5 sites.</p>
<pre>pip install virtualenv</pre>
<h4>Virtualenvwrapper</h4>
<p>Virtualenvwrapper contains a bunch of convenience scripts for working with your virtualenvs.</p>
<pre>pip install virtualenvwrapper</pre>
<p>Before we continue, log out of your shell, then log back in so you have access to the virtualenvwrapper scripts.</p>
<pre>mkvirtualenv <proj_name> --no-site-packages --distribute
workon <proj_name>
cdvirtualenv</pre>
<h3><span>Mezzanine</span></h3>
<pre><em># Install from PyPI</em>
$ pip install mezzanine<br>$ pip install fabric<br><br><em># Create a project<br></em>$ mezzanine-project <myproject><br>$ cd <myproject></pre>
<p>More instructions for working with Mezzanine can be found <a href="http://mezzanine.jupo.org/docs/">here</a>.</p>
<h3>Vagrant</h3>
<p>You need Ruby on your system to get this to work. My <a href="https://gist.github.com/4534579">Vagrantfile</a> has can be used as an example.</p>
<pre>$ gem install vagrant
$ vagrant box add precise64 http://files.vagrantup.com/precise64.box
$ vagrant init precise64
$ vagrant up</pre>
<h3>Git</h3>
<p>On your favorite git host, create a repository for your project. Note the repository's URL. Make sure you have git installed on localhost, then in your <myproject> directory run:</p>
<pre>$ git init
$ git remote add origin <repository_url></pre>
<p>I usually make these repositories private. If you do that, you will want to add a deploy key to your host repository.</p>
<pre>$ vagrant ssh<br>$ ssh-keygen -t rsa -C "<email_address>"<br><em># Hit return through the options.<br></em><br>$ cat ~/.ssh/id_rsa.pub<br><em># Copy the output and add it as a new key for your host.<br># Yes, I know about pbcopy. No, it does not work over ssh. </em></pre>
<p>More instructions on using ssh deploy keys can be found <a href="https://help.github.com/articles/generating-ssh-keys">here for github</a> or <a href="https://confluence.atlassian.com/display/BITBUCKET/Set+up+SSH+for+Git">here for bitbucket</a>. </p>
<p>Add your <myproject> directory to git and push it on up to origin!</p>
<pre>$ git add .<br>$ git commit -m 'Initial commit'<br>$ git push origin master</pre>
<h3>Git Alternative</h3>
<p>Networks being what they are, relying on an outside resource like github can be risky. I usually come up with the most proper solutions when far removed from network access. By design, every git repository is created equal, so there is nothing special about a hosted repository versus your local repo. Built into git is the `git daemon` commnd. Simply issue the command</p>
<pre>$ git daemon --verbose --export-all --base-path=/path/to/your/repositories</pre>
<p>to start a git daemon. Instructions abound on the internet for GNU/Linux init.d scripts and Mac launchd plists. Modify your settings.FABRIC REPO_URL value appropriately. For example, my Vagrant guest expects the following value:</p>
<pre>"REPO_URL": "git://10.0.2.2/<repo>"</pre>
<p>Now I can update and commit my changes on localhost, then run a `fab deploy` to see my changes reflected on the guest OS.</p>
<h3>Intermission</h3>
<p>At this point, you should have a Mezzanine project running inside of a virtualenv and an Ubuntu 12.04 Precise Pangolin Vagrant up and running and your code committed to a git or mercurial repository.</p>
<h3>Code Up</h3>
<p>In your project's <a href="https://github.com/stephenmcd/mezzanine/blob/master/mezzanine/project_template/settings.py">settings.py</a>, uncomment FABRIC dictionary. Paste those lines into your local_settings.py. The production values can be put in your settings.py. In local_settings.py, let's put the values in for that Vagrant.</p>
<pre>FABRIC = {<br> "SSH_USER": "vagrant", # SSH username<br> "SSH_PASS": "vagrant", # SSH password (consider key-based authentication)<br> "HOSTS": ['<host-name>', ], # List of host names or IPs.<br> "VIRTUALENV_HOME": "/home/vagrant", # Absolute remote path for virtualenvs<br> "PROJECT_NAME": "<project_name>", # Unique identifier for project<br> "REQUIREMENTS_PATH": "requirements/project.txt", # Path to pip requirements, relative to project<br> "GUNICORN_PORT": 8000, # Port gunicorn will listen on<br> "LOCALE": "en_US.UTF-8", # Should end with ".UTF-8"<br> "LIVE_HOSTNAME": "example.com", # Host for public site.<br> "REPO_URL": "<repository_url>",<br> "DB_PASS": "default", # Live database password<br> "ADMIN_PASS": "default", # Live admin user password<br> "SECRET_KEY": <secret_key><br>}</pre>
<h3>Deploy</h3>
<p>Mezzanine's excellent <a href="https://github.com/stephenmcd/mezzanine/blob/master/mezzanine/project_template/fabfile.py">fabfile.py</a> dropped in <a href="https://github.com/stephenmcd/mezzanine/commit/ebe380f1b0daf0d013c7e33d5209086aadf1acfe#mezzanine/project_template/fabfile.py">May 2012</a>. For what it does, it remains quite lean. To deploy your server for the first time run:</p>
<pre>$ fab all</pre>
<p>This will install and update the required OS packages, create the virtualenv, initialize the database, the web server, and start the web application. After you make changes, commit them to your SCM, and push to your repository, `fab deploy` will pull your changes, make all the necessary updates, and restart the appropriate services.</p>
<h3>Underkill?</h3>
<p>Why don't I use Puppet or Chef? These tools are great for large web applications that span multiple systems. As a rule, I want to use the fewest and simplest tools possible to get the job done. If I needed to deploy a seperate database or load balancers, I would certainly go with Puppet. In fact, writing a pp file to facilitate scaling this up may be my next article. In all likelihood, though, a proper Puppet (or Chef, or Buildout) would rely heavily on Fabric or Capistrano for the final deploy. The conventional wisdom is that incremental Continuous Deployment is better than none. When a Mezzanine infrastructure needs to scale beyond a single host, you can address it confident in the knowledge that the single-host deploy is rock solid.</p>