<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>maxgarrick.com &#187; System Administration</title>
	<atom:link href="http://maxgarrick.com/category/sysadmin/feed/" rel="self" type="application/rss+xml" />
	<link>http://maxgarrick.com</link>
	<description>Come take a look under the hood</description>
	<lastBuildDate>Sun, 08 Mar 2009 23:32:09 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>8 ModSecurity Tips for a Successful Roll-out</title>
		<link>http://maxgarrick.com/8-modsecurity-tips/</link>
		<comments>http://maxgarrick.com/8-modsecurity-tips/#comments</comments>
		<pubDate>Sun, 08 Mar 2009 20:48:07 +0000</pubDate>
		<dc:creator>max</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[modsecurity]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[tips]]></category>

		<guid isPermaLink="false">http://maxgarrick.com/?p=138</guid>
		<description><![CDATA[A short while ago we rolled out ModSecurity on three of our Apache web servers.  The benefits of ModSecurity are clear: protection against most blatant web-based attacks, like SQL Injection and Cross-site scripting.  It also acts as a last line of defense against information leakage, like PHP errors and directory listings.
In reality, ModSecurity [...]]]></description>
			<content:encoded><![CDATA[<p>A short while ago we rolled out ModSecurity on three of our Apache web servers.  The benefits of ModSecurity are clear: protection against most blatant web-based attacks, like SQL Injection and Cross-site scripting.  It also acts as a last line of defense against information leakage, like PHP errors and directory listings.</p>
<p>In reality, ModSecurity takes a lot of time to implement well, especially if you have a large site.  The core rules will almost certainly block legitimate user behavior&#8211;interrupting their business process with a generic error message.</p>
<p>Here are 8 tips that can help make your ModSecurity roll-out a success.</p>
<ol>
<li>Configure the ModSecurity SecResponseBodyLimit to be at least as large as the largest text document served by the site.  Even in log-only mode, this will block large response bodies!</li>
<li>Configure the ModSecurity SecRequestBodyInMemoryLimit to be at least as large as the size of php&#8217;s upload_max_filesize limit.  Again, ModSecurity will block file uploads that exceed this value&#8211;even in log only mode.</li>
<li>Start in log-only mode.  ModSecurity will tell you what it would have blocked, giving you an opportunity to add whitelist rules or otherwise tune you ruleset.</li>
<li>Whitelist load balancer health checks.  This usually involves adding a whitelist rule for the load balancer&#8217;s IP.</li>
<li>Whitelist automation and APIs that requests HTTP documents.  This usually involves either an IP, user-agent, or URL-based whitelist.  These are often easy to miss amongst the torrent of alerts ModSecurity detects.</li>
<li>Consider disabling audit logging for invalid user agents, missing accept header, and unacceptable HTTP headers.  This will significantly reduce the number of alerts that need to be analyzed, improving the chance of finding an alert that really matters.</li>
<li>Review apps that use WSIWIG editors to ensure they are validating and sanitizing user input properly.  ModSecurity loves to block WSIWIG input, generating alerts ranging from SQL injection to XSS to system command injection.  The way around this is to whitelist certain rules for these app URLs.</li>
<li>Create an operational plan to regularly review and act on ModSecurity alerts.  Consider using ModSecurity Console to reduce the amount of time needed to analyze audit logs.
</ol>
]]></content:encoded>
			<wfw:commentRss>http://maxgarrick.com/8-modsecurity-tips/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Reverse proxy with nginx</title>
		<link>http://maxgarrick.com/reverse-proxy-with-nginx/</link>
		<comments>http://maxgarrick.com/reverse-proxy-with-nginx/#comments</comments>
		<pubDate>Sun, 30 Nov 2008 05:08:41 +0000</pubDate>
		<dc:creator>max</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[centos]]></category>
		<category><![CDATA[mod_rpaf]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[reverse proxy]]></category>

		<guid isPermaLink="false">http://maxgarrick.com/?p=55</guid>
		<description><![CDATA[In this post I hope to show how to configure nginx as a reverse proxy to a back-end CentOS 5 server running Apache.
When you add an nginx reverse proxy layer on top of Apache, Apache thinks that all connections originate from the server running nginx.  This creates a couple annoying problems:

Every entry in the [...]]]></description>
			<content:encoded><![CDATA[<p>In this post I hope to show how to configure nginx as a reverse proxy to a back-end CentOS 5 server running Apache.</p>
<p>When you add an nginx reverse proxy layer on top of Apache, Apache thinks that all connections originate from the server running nginx.  This creates a couple annoying problems:</p>
<ul>
<li>Every entry in the Apache access logs appears to come from the IP of the nginx server</li>
<li>Securing sessions by checking that a user&#8217;s IP address hasn&#8217;t changed becomes more difficult.
<ul>
<li>This is especially true when using open source software.  OS packages usually look for the client&#8217;s IP in the REMOTE_ADDR variable.</li>
</ul>
</li>
</ul>
<p>To resolve these issues, we&#8217;ll use the Apache mod_rpaf module to populate the REMOTE_ADDR using a special HTTP header inserted by nginx.  A typical request would work as follows:</p>
<ul>
<li>1.2.3.4 sends HTTP request to nginx server</li>
<li>nginx determines that it needs to proxy pass the request to a back-end Apache server (e.g. by looking at the content-type or virtual host).</li>
<li>nginx adds an HTTP header &#8220;X-Forwarded-For&#8221; with the client&#8217;s real IP</li>
<li>nginx forwards (proxy_pass) the request to back-end Apache server</li>
<li>mod_rpaf in Apache detects that the request is coming from the nginx IP, then substitutes REMOTE_ADDR with the contents of X-Forwarded-For</li>
<li>Apache handles request as normal.  Applications do not need to be aware of the reverse proxy.</li>
</ul>
<p>To install mod_rpaf on the CentOS 5 box:</p>
<pre class="brush: bash">
wget http://stderr.net/apache/rpaf/download/mod_rpaf-0.6.tar.gz
tar zxvf mod_rpaf-0.6.tar.gz
cd mod_rpaf-0.6

# Patch Makefile so it looks for &#039;apxs&#039; instead of &#039;apxs2&#039; (required
# when compiling under CentOS 5):
sed -ie &#039;s/apxs2/apxs/&#039; Makefile

make rpaf-2.0
make install-2.0
</pre>
<p>Create /etc/httpd/conf.d/rpaf.conf:</p>
<pre class="brush: php">
# Path to mod_rpaf-2.0.so, relative to /etc/httpd/
LoadModule rpaf_module modules/mod_rpaf-2.0.so

RPAFenable On
RPAFsethostname On

# Define our reverse proxy IP.  Only substitute client IP in
# when we receive a request from this IP.
RPAFproxy_ips 192.168.0.1

# The header where the real client IP address is stored.
RPAFheader X-Forwarded-For
</pre>
<p>Configure nginx to reverse proxy our CNAME IP address to the back-end container.  We won&#8217;t go into installing nginx here, instead I&#8217;ve included the relevant configuration section in /etc/nginx/nginx.conf.  This configuration says to reverse proxy all requests to the virtual host &#8216;myvirtualhost.com&#8217;:</p>
<pre class="brush: php">
server {
listen 80;
server_name myvirtualhost.com;

location / {
proxy_pass http://192.168.0.56;
proxy_redirect default;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
</pre>
<p>After restarting Apache &amp; nginx, you should be able to successfully connect to your back-end Apache via the nginx reverse proxy layer.  Inspecting the Apache environment will show a couple new headers, but other than that requests look the same as if clients were connecting directly without the proxy.</p>
]]></content:encoded>
			<wfw:commentRss>http://maxgarrick.com/reverse-proxy-with-nginx/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>How to create a minimal LAMP stack in OpenVZ</title>
		<link>http://maxgarrick.com/how-to-create-a-minimal-lamp-stack-in-openvz/</link>
		<comments>http://maxgarrick.com/how-to-create-a-minimal-lamp-stack-in-openvz/#comments</comments>
		<pubDate>Sun, 30 Nov 2008 00:01:38 +0000</pubDate>
		<dc:creator>max</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[openvz]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tuning]]></category>

		<guid isPermaLink="false">http://maxgarrick.com/?p=36</guid>
		<description><![CDATA[Creating a minimal LAMP stack in OpenVZ:
Start with a pre-created centos-5 OpenVZ template &#38; install required packages:


# Create centos-5 OpenVZ container:
vzctl create 1056 --ostemplate centos-5-x86_64-minimal
vzctl set 1056 --ipadd 192.168.0.56 --nameserver 123.123.123.123 --save
vzctl start 1056

# Update software &#38; install packages:
vzctl 1056 install yum
vzctl enter 1056
yum upgrade

# Install packages -- the &#34;.x86_64&#34; tells yum to only
# install [...]]]></description>
			<content:encoded><![CDATA[<p>Creating a minimal LAMP stack in OpenVZ:</p>
<p>Start with a pre-created centos-5 OpenVZ template &amp; install required packages:</p>
<pre class="brush: bash">

# Create centos-5 OpenVZ container:
vzctl create 1056 --ostemplate centos-5-x86_64-minimal
vzctl set 1056 --ipadd 192.168.0.56 --nameserver 123.123.123.123 --save
vzctl start 1056

# Update software &amp; install packages:
vzctl 1056 install yum
vzctl enter 1056
yum upgrade

# Install packages -- the &quot;.x86_64&quot; tells yum to only
# install the 64-bit packages and not the i386 packages.
yum install vim-enhanced.x86_64 mysql.x86_64 mysql-server.x86_64 \
httpd.x86_64 httpd-devel.x86_64 wget.x86_64 which.x86_64 \
php.x86_64 make.x86_64 gcc.x86_64 gcc-c++.x86_64

# Clean up leftover files from yum:
yum clean all
</pre>
<p>Next, tune Apache to fit our development 256MB OpenVZ container. If you have more memory dedicated to your container, consider increasing these settings. Edit the prefork MPM section of /etc/httpd/conf/httpd.conf:</p>
<pre class="brush: php">
&lt;span class=&quot;__mozilla-findbar-search&quot; style=&quot;padding: 0pt; background-color: white; color: black; display: inline; font-size: inherit;&quot;&gt;&amp;lt;&lt;/span&gt;IfModule prefork.c&lt;span class=&quot;__mozilla-findbar-search&quot; style=&quot;padding: 0pt; background-color: white; color: black; display: inline; font-size: inherit;&quot;&gt;&amp;gt;&lt;/span&gt;
StartServers       2
MinSpareServers    1
MaxSpareServers   8
ServerLimit      8
MaxClients       8
MaxRequestsPerChild  4000
&lt;span class=&quot;__mozilla-findbar-search&quot; style=&quot;padding: 0pt; background-color: white; color: black; display: inline; font-size: inherit;&quot;&gt;&lt;span class=&quot;__mozilla-findbar-search&quot; style=&quot;padding: 0pt; background-color: white; color: black; display: inline; font-size: inherit;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&amp;lt;/IfModul&lt;span class=&quot;__mozilla-findbar-search&quot; style=&quot;padding: 0pt; background-color: white; color: black; display: inline; font-size: inherit;&quot;&gt;&lt;span class=&quot;__mozilla-findbar-search&quot; style=&quot;padding: 0pt; background-color: white; color: black; display: inline; font-size: inherit;&quot;&gt;e&amp;gt;&lt;/span&gt;&lt;/span&gt;
</pre>
<p>Let&#8217;s lock down the MySQL root user before starting up services:</p>
<pre class="brush: bash">
mysql -u root mysql
mysql&gt; update user set password=password(&#039;mynewsecurepassword&#039;) \
where user=&#039;root&#039;;
mysql&gt; flush privileges;
mysql&gt; exit
</pre>
<p>Start services and ensure that services start when the machine boots up:</p>
<pre class="brush: bash">
chkconfig --levels 345 httpd
chkconfig --levels 345 mysqld
service httpd start
service mysqld start
</pre>
<p>Finally: test!</p>
<p>This will give you a slimmed down LAMP stack, suitable for running small web applications on top.</p>
]]></content:encoded>
			<wfw:commentRss>http://maxgarrick.com/how-to-create-a-minimal-lamp-stack-in-openvz/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Solaris 10 + ZFS + Sunfire X4500</title>
		<link>http://maxgarrick.com/solaris-10-zfs-sunfire-x4500/</link>
		<comments>http://maxgarrick.com/solaris-10-zfs-sunfire-x4500/#comments</comments>
		<pubDate>Mon, 24 Nov 2008 03:55:29 +0000</pubDate>
		<dc:creator>max</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[storage]]></category>
		<category><![CDATA[sun]]></category>
		<category><![CDATA[thumper]]></category>
		<category><![CDATA[zfs]]></category>

		<guid isPermaLink="false">http://maxgarrick.com/?p=24</guid>
		<description><![CDATA[ZFS is rapidly bringing &#8220;enterprise&#8221; features you&#8217;d normally find in Netapp, EMC or IBM products.  We recently deployed a Sunfire X4500 as our main storage server, serving out iSCSI and NFS shares to multiple servers, including an OpenVZ hardware node.  The Sunfire X4500 attracted us for two reasons: ZFS and cost of ownership.
The Sunfire X4500 [...]]]></description>
			<content:encoded><![CDATA[<p>ZFS is rapidly bringing &#8220;enterprise&#8221; features you&#8217;d normally find in Netapp, EMC or IBM products.  We recently deployed a Sunfire X4500 as our main storage server, serving out iSCSI and NFS shares to multiple servers, including an OpenVZ hardware node.  The Sunfire X4500 attracted us for two reasons: ZFS and cost of ownership.</p>
<p>The Sunfire X4500 came with 48 500GB drives and 6 disk controllers.  We configured the array into 7 RAIDZ2 sets, then striped the 7 sets together, leaving 4 spares and two root disks.  Since we started with Solaris 5/08, we went with a ufs mirror for the two root disks (Solaris 10/08 lets you use ZFS root pool).  This gives us plenty of redundancy at the disk and controller level.</p>
<p>Next we set up several ZFS filesystems, essentially one filesystem for each website using NFS, and one ZFS volume for each iSCSI share.  For now, we are only using one iSCSI share &#8212; this will change soon.</p>
<p>The filesystems exported over NFS have no capacity limits, while the iSCSI volume was thin provisioned at 1TB.  We are currently using only using about 100GB of the iSCSI volume.  In the long run the thin provisioned volume will save us from having to resize the volume and extend the ext3 filesystem that sits on top.</p>
<p>The iSCSI volume was shared to an Redhat RHEL5 box running Open-iSCSI.  We found Open-iSCSI to generally work well until you have a network hiccup.  In our initial tests, a network delay of 3 seconds would cause the SCSI block device to disappear temporarily, freaking ext3 out and remounting read-only.</p>
<p>Our solution to network hiccups was to add a DM-Multipath layer between the iSCSI and ext3 layers on the RHEL box.  Multipath will sense network issues and queue I/O until the issue is resolved, or a configurable timeout expires.  The queuing behavior worked perfectly as we went about unpluging and pluging network cables on the RHEL box.  Side note: Multipath is a much more capable piece of software, allowing a machine to switch from one network path to another if it had redundant network paths to the SAN.</p>
<p>One gotcha to look out for when using a Solaris + RHEL5 + Multipath combo: a bug on the Solaris iSCSI target side causes the SCSI ID to be reported as much longer than Multipath can handle.  We got around the bug by extracting what appeared to be the unique SCSI ID portion.</p>
<p>Performance was near wire-spead for sequential I/O.  Random I/O was fantastic, thanks in large part to the 16GB of RAM the Sunfire was using as a giant disk cache.  The I/O performance was much better than the local SATA that the RHEL box came with.</p>
<p>With the iSCSI share created, shared, all appropriate iptables/ipf rules were set up, and the block device mounted, we then moved all of the OpenVZ containers to this RHEL box.  OpenVZ needed no special configuration &#8212; we simply mounted the iSCSI device on /vz using ext3.  All containers have been running smoothly since (except for a bad RAM module, but that was unrelated to iSCSI or OpenVZ).</p>
<p>The NFS shares have also been running smoothly, although we did run into a nasty Solaris ipf issue.  The problem is that after a few days, automountd on RHEL randomly hangs when attempting an additional mount.  Packet captures indicate that ipf is blocking either the inbound or outbound packets for the second TCP connection (we are not using UDP) to the &#8216;nfs&#8217; port.  Disabling ipf immediately resolves the problem.  We are currently trying to reproduce the issue on a test server.</p>
<p>Even with the few issues that came up, we are still very happy with our new setup.  The Sunfire X4500, ZFS, and Solaris 10 matches many of the essential features of a more expensive &#8220;enterprise&#8221; solution.</p>
]]></content:encoded>
			<wfw:commentRss>http://maxgarrick.com/solaris-10-zfs-sunfire-x4500/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Two extremely informative ZFS references</title>
		<link>http://maxgarrick.com/two-extremely-informative-zfs-references/</link>
		<comments>http://maxgarrick.com/two-extremely-informative-zfs-references/#comments</comments>
		<pubDate>Wed, 15 Oct 2008 17:45:40 +0000</pubDate>
		<dc:creator>max</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[zfs]]></category>

		<guid isPermaLink="false">http://maxgarrick.com/?p=19</guid>
		<description><![CDATA[Two extremely informative ZFS references:
http://www.solarisinternals.com/wiki/index.php/ZFS_Best_Practices_Guide
http://www.solarisinternals.com/wiki/index.php/ZFS_Evil_Tuning_Guide
]]></description>
			<content:encoded><![CDATA[<p>Two extremely informative ZFS references:</p>
<p>http://www.solarisinternals.com/wiki/index.php/ZFS_Best_Practices_Guide</p>
<p>http://www.solarisinternals.com/wiki/index.php/ZFS_Evil_Tuning_Guide</p>
]]></content:encoded>
			<wfw:commentRss>http://maxgarrick.com/two-extremely-informative-zfs-references/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Understanding OpenVZ resource limits</title>
		<link>http://maxgarrick.com/understanding-openvz-resource-limits/</link>
		<comments>http://maxgarrick.com/understanding-openvz-resource-limits/#comments</comments>
		<pubDate>Sun, 12 Oct 2008 04:14:51 +0000</pubDate>
		<dc:creator>max</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[openvz]]></category>
		<category><![CDATA[resource]]></category>
		<category><![CDATA[ubc]]></category>

		<guid isPermaLink="false">http://maxgarrick.com/?p=15</guid>
		<description><![CDATA[OpenVZ resource limits can be a little tricky, even after reading through the documentation on the OpenVZ website.  With this post, I hope to explain the /proc/user_beancounters file as well as provide an illustration of memory guarantees/limits in an example 256mb container.
Before attempting to understand OpenVZ&#8217;s memory limits, let&#8217;s recap Linux&#8217;s memory setup.  This [...]]]></description>
			<content:encoded><![CDATA[<p>OpenVZ resource limits can be a little tricky, even after reading through the documentation on the <a href='http://wiki.openvz.org/UBC_parameters'>OpenVZ website</a>.  With this post, I hope to explain the /proc/user_beancounters file as well as provide an illustration of memory guarantees/limits in an example 256mb container.</p>
<p>Before attempting to understand OpenVZ&#8217;s memory limits, let&#8217;s recap Linux&#8217;s memory setup.  This background information is important to firmly grasp OpenVZ&#8217;s behavior.  You can safely skip this section if you already understand Linux&#8217;s <a href='http://www.mjmwired.net/kernel/Documentation/vm/overcommit-accounting'>memory overcommit accounting</a>.</p>
<h1>Linux Overcommit Accounting</h1>
<p>Memory in Linux refers to the combined RAM + swap values.  Memory is allocated from this pool using one of the *alloc() functions.  If malloc() is used to allocate memory, the pages are not zeroed out.  malloc() is unique in one regard: the kernel can malloc() more memory than what is available in RAM + swap.  This behavior of allocating more than the total available memory is called <strong>overcommitting</strong> memory.</p>
<p>Seems like a recipe for disaster, huh?  Imagine&#8230; processes are humming along allocating memory and BAM! some process wants to use the n&#8217;th + 1 byte of memory and an out of memory (OOM) condition provokes the kernel to start killing processes.</p>
<p>Why does the kernel allow memory to be overcommitted?  Because most applications do not actually <strong>consume</strong> all of the malloc()&#8217;d memory.  If an app doesn&#8217;t use a memory location, it does not really need to subtract from your total available memory.</p>
<p>Consider a typical Apache process.  A full 20-30% of an Apache processes malloc()&#8217;d memory may not be consumed.  With memory overcommit, this slice of memory can be used by other applications.  Java applications also allocate much more than they use, as do many scientific applications.</p>
<p>At the system-wide level, these &#8220;malloc&#8217;d(), but not consumed&#8221; slices of memory begin to add up.  By overcommitting memory, these slices don&#8217;t take up physical memory locations &#8212; resulting in more efficient use of memory resources.</p>
<h1>OpenVZ and memory overcommit</h1>
<p>OpenVZ also has the ability to overcommit memory.  When creating an OpenVZ container, we specify the vmguarpages and oomguarpages resource guarantees.  vmguarpages represents the maximum guaranteed amount of <strong>malloc()&#8217;d</strong> memory a container may have, while oomguarpages represents the maximum <strong>consumed</strong> memory.  These are called guarantees because (If your server has enough RAM + swap) container processes will never be killed due to OOM if they are within these limits.</p>
<p>What if your container exceeds the vmguarpages or oomguarpages value?  This is where a new limit comes in: privvmpages.  privvmpages represents the absolute upper limit on container memory.  When you run free or `cat /proc/meminfo` in a container, you see this privvmpages value take form as &#8220;Total memory&#8221;.</p>
<p>The memory gap between privvmpages and the two resource guarantees (vmguarpages and oomguarpages) is <strong>not safe to use in an ongoing basis if the sum of all container privvmpages exceeds RAM + swap of the hardware node</strong>.  This is because if the hardware node runs out of memory, it begins looking for containers using more than their guaranteed memory.  The kernel kills a process from the container who&#8217;s physpages exceeds oomguarpages the most.</p>
<p>I&#8217;ve created a diagram that hopefully illustrates the relationship between these three key memory limits/guarantees.  Also included in the diagram is kmemsize, which is used for non-swappable kernel memory&#8211;not very important as long as it scales with privvmpages.</p>
<p><img class="alignnone" src="http://maxgarrick.com/wp-content/uploads/vz.png" alt="OpenVZ memory constraints" /></p>
]]></content:encoded>
			<wfw:commentRss>http://maxgarrick.com/understanding-openvz-resource-limits/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Get your dev server, $0.10 a pop</title>
		<link>http://maxgarrick.com/get-your-dev-server-010-a-pop/</link>
		<comments>http://maxgarrick.com/get-your-dev-server-010-a-pop/#comments</comments>
		<pubDate>Tue, 22 Apr 2008 02:50:55 +0000</pubDate>
		<dc:creator>max</dc:creator>
				<category><![CDATA[System Administration]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[openvz]]></category>

		<guid isPermaLink="false">http://maxgarrick.com/?p=14</guid>
		<description><![CDATA[One of the best uses of virtualization technology is for creating development environments.  Virtual private servers (VPS) are ideal if you need a sandbox to create a new application stack, develop a new web app, or test out the app under a variety of Q/A scenarios.
How can we offer dev environments with low provisioning [...]]]></description>
			<content:encoded><![CDATA[<p>One of the best uses of virtualization technology is for creating development environments.  Virtual private servers (VPS) are ideal if you need a sandbox to create a new application stack, develop a new web app, or test out the app under a variety of Q/A scenarios.</p>
<p>How can we offer dev environments with low provisioning cost?  This is one way:</p>
<ul>
<li>Set up OpenVZ on a RHEL5 server.</li>
<li>Set up a web template (Apache, PHP5).</li>
<li>Set up a MySQL template</li>
<li>For each dev environment, deploy a web and MySQL container.</li>
</ul>
<p>This 4 step process glosses over many important challenges.  For instance:</p>
<ul>
<li>How do you access these machines over the network?</li>
<li>How to get the latest code into each deployed web container?</li>
<li>How to get the latest MySQL schema &amp; associated dev data into the MySQL container?</li>
<li>How to get code and schema changes out of the container and into another environment (e.g.: deploying to production)?</li>
<li>How to upgrade/restart the VPS without having to coordinate with each developer?</li>
</ul>
<p>I&#8217;m thinking we can overcome these challenges with some crafty configuration &amp; scripts.</p>
<h2>Network access</h2>
<p>NAT all VPS servers for more fluid provisioning, less DNS updates.  Web nodes occupy one network subnet, DB nodes occupy another.  Use a database to track all VPS and build a simple webapp on top that provides bookmarks to each VPS along with CRUD ops.</p>
<h2>Getting code into the VPS</h2>
<p>Using our git repo, check out a working copy with the latest dev branch.  Alternatively, NFS mount staff home directories in each VPS and work off that.  I&#8217;d prefer the NFS approach, as it makes the VPS more transient: we can destroy and re-create the server using an upgraded template if desired without loosing code.</p>
<h2>Getting DB schema into the VPS</h2>
<p>Database migrations, similar to Rails (we use PHP for most apps).  Moodle CMS also has a form of database migrations which happen via the web, which is a tad simpler.  <a href="http://www.phpdoctrine.org/">Doctrine</a> ORM supports database migrations, although we use it only for new development and it won&#8217;t help our existing code.  For older/legacy webapps, we&#8217;ll have to maintain a per-tool schema file to bootstrap our webapps.</p>
<h2>Getting code and schema updates out of the VPS</h2>
<p>Pull code changes using git into a central repo.  Put all database migrations in the code, using Doctrine as described above, or schema bootstrap file.</p>
<h2>Painless VPS reboots</h2>
<p>If all database changes exist in code, and all code exists on the shared NFS server, then destroying &amp; deploying a new VPS from an updated template should not impact a developer.  Test data may disappear, which may cause concern.  Ideally, all important data would be saved in-code and easily imported into MySQL, through migrations or bootstrap SQL files.   Alternatively, we could place the MySQL data files on an iSCSI lun, at an additional provisioning cost.</p>
<p>Once we are able to quickly provision new dev environments, why not do the same for production apps?  I think we could use the same code bootstrap &amp; database migration code to deploy new application stacks on demand.</p>
]]></content:encoded>
			<wfw:commentRss>http://maxgarrick.com/get-your-dev-server-010-a-pop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
