<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[mewm blog]]></title><description><![CDATA[Dev stuff]]></description><link>https://blog.mewm.org/</link><image><url>https://blog.mewm.org/favicon.png</url><title>mewm blog</title><link>https://blog.mewm.org/</link></image><generator>Ghost 3.6</generator><lastBuildDate>Wed, 15 Apr 2026 20:49:43 GMT</lastBuildDate><atom:link href="https://blog.mewm.org/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Adding New Relic APM and SERVERS monitoring to your dockerized ghost app]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>In <a href="http://blog.mewm.org/ghost-mariadb-with-docker-fig">previous post</a>, we went through setting up a basic ghost application and it's dependencies separated in docker containers, and orchestrating it all with docker-compose.<br>
In this small article, we will go through modifying the ghost application from the previous post, to include New Relic APM library, to monitor the</p>]]></description><link>https://blog.mewm.org/adding-new-relic-monitoring-to-your-dockerized-ghost-app/</link><guid isPermaLink="false">5e4da3940a5a2900013fe97a</guid><dc:creator><![CDATA[Dennis Micky Jensen]]></dc:creator><pubDate>Tue, 10 Mar 2015 22:59:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>In <a href="http://blog.mewm.org/ghost-mariadb-with-docker-fig">previous post</a>, we went through setting up a basic ghost application and it's dependencies separated in docker containers, and orchestrating it all with docker-compose.<br>
In this small article, we will go through modifying the ghost application from the previous post, to include New Relic APM library, to monitor the Express served ghost application.<br>
To finish up, we'll add the New Relic SERVERS library as a separate container, to monitor the actual server that are hosting the containers.<br>
And although this article is based on code from a previous post, the instructions to setup the New Relic libraries should me somewhat applicable to other setups.</p>
<p>New Relic offers several different libraries to monitor all aspects of your application and architecture. They all integrate really smoothly, so dockerizing these libraries are pretty trivial. Best of all, they offer a free LITE subscription! - I fucking love free shit!</p>
<p>As base source, I'm using the results from <a href="http://blog.mewm.org/ghost-mariadb-with-docker-fig">previous post</a>.<br>
The final code after the implementations elaborated in this article, can be found in a <a href="https://github.com/mewm/ghost-mariadb-docker/tree/02-adding-new-relic-blog">branch in the github repo.</a>. The master branch has probably diversified by now.<br>
I'm gonna assume you've read the previous post, as I'm gonna show partial chunks of that source.</p>
<h2 id="problem">Problem</h2>
<p>I want to monitor the performance and behaviour of my ghost application. The installation should be included in the docker container housing the actual ghost application/site.</p>
<p>I also want to monitor the actual server, that are hosting all the docker containers. This tool should be added in a separate container.</p>
<h2 id="objectives">Objectives</h2>
<ul>
<li><a href="#newrelic-apm">Create and add New Relic APM install bash script</a></li>
<li><a href="#run-ghost">Modify the ghost <code>run-ghost.sh</code> init script</a>, to run our New Relic install script</li>
<li><a href="#new-relic-docker">Add New Relic SERVERS docker container to <code>docker-compose.yml</code></a></li>
</ul>
<p><a id="newrelic-apm"></a></p>
<h3 id="newrelicapmbashinstallscript">New Relic APM bash install script</h3>
<p>When you've fetched your API key, we need to write a bash script which installs the <a href="https://www.npmjs.com/package/newrelic">new relic npm module</a>, copies the <code>newrelic.js</code> file, and makes the nessecary changes inject the module into ghost. Here is how <code>install_newrelic.sh</code> looks like:</p>
<pre><code class="language-bash">echo &quot;Installing new relic!&quot;

npm install newrelic
cp node_modules/newrelic/newrelic.js newrelic.js

sed -i -r &quot;s/My Application/mewm blog/&quot; newrelic.js
sed -i -r &quot;s/info/trace/&quot; newrelic.js 
sed -i -r &quot;s/license key here/${1}/&quot; newrelic.js 
sed -i &quot;1ivar newrelic = require('newrelic');&quot; index.js 
</code></pre>
<p>This installs the npm module, and and copies the config file. We use <code>sed</code> to replace the mandatory values in <code>newrelic.js</code>.<br>
In the first <code>sed</code>, we switch the name of what's gonna pop up in the New Relic console.<br>
The API key is taken from the first command line argument.<br>
The info/trace value determines the aggresiveness of the monitoring. <code>trace</code> is the most meticulous, while <code>info</code> and up has less performance overhead.<br>
The last line, injects the <code>require()</code> statement in to the first line in the ghost <code>index.js</code>.</p>
<p>We also need to change the <code>Dockerfile</code> for the ghost application, to add the install script during build. This is a line consisiting of <code>ADD install_newrelic.sh /install_newrelic.sh</code> - Ive added that line right under the <code>ADD</code> command, that adds the <code>run-ghost.sh</code> file.</p>
<p><a id="run-ghost"></a></p>
<h3 id="ghostrunscriptalterations">Ghost run script alterations</h3>
<p>The <code>run-ghost.sh</code> is our default command for the docker container, which is housing ghost. We need to modify it, so it runs the <code>install_newrelic.sh</code>. This is just the top of the file. The rest is elaborated <a href="http://blog.mewm.org/ghost-mariadb-with-docker-fig">here</a></p>
<pre><code class="language-bash">#!/bin/bash
NEW_RELIC=&quot;${NEW_RELIC_LICENSE_KEY:=0}&quot;

if [ &quot;${NEW_RELIC}&quot; != &quot;0&quot; ] &amp;&amp; [ &quot;${NODE_ENV}&quot; = &quot;production&quot; ]; then
	sh /install_newrelic.sh ${NEW_RELIC}
fi
.....................
.....................
</code></pre>
<p>Here, we basically make sure, that if we have an API key provided, and we're in node production mode, we run our new relic install script, with the API key, as first argument.<br>
If you do not provide an API key in <code>docker-compose.yml</code>, this step will be skipped.</p>
<p>After rebuilding and booting your new container, after a few minutes, you should be able to see some metrics in the New Relic console. You'll also be able to see performance stats for your database.</p>
<p><a id="new-relic-docker"></a></p>
<h3 id="newrelicserversdockercontainer">New Relic SERVERS docker container</h3>
<p>There is a pre-built image out there, which takes care of setting up the New Relic server daemon, to provide server stats. In fact, we can keep the instructions only to the <code>docker-compose.yml</code> file. Here is a paste of the modified <code>docker-compose.yml</code>:</p>
<pre><code class="language-Dockerfile">data:
  build: ./data
  volumes:
    - /var/lib/mysql
    - /var/www/ghost/content
#    - /Users/mewm/www/ghost-theme:/var/www/ghost/content/themes/casper This can be added for theme development. Comment out the theme stuff in run-ghost.sh before rebuilding
db:
  build: ./mariadb
  ports:
    - &quot;3305:3305&quot;
  volumes_from:
    - data
  environment:
    - DEFAULT_USER=ghost # A user with this name will be created
    - DEFAULT_PASS=foobarbaz
    - PORT=3305
web:
  build: ./ghost
  ports:
    - &quot;2368:2368&quot;
  links:
    - db:database
  volumes_from:
    - data
  environment:
    - DB_HOST=database
    - DB_CLIENT=mysql
    - DB_USER=ghost
    - DB_PASSWORD=foobarbaz
    - DB_PORT=3305
    - DB_DATABASE=ghost
    - NODE_ENV=production
    - URL=http://blog.mewm.org
    - THEME_SOURCE=https://github.com/mewm/ghost-theme # Git repo to fetch theme from
    - NEW_RELIC_LICENSE_KEY=&lt;api key here&gt;
newrelicservermon:
  image: uzyexe/newrelic
  hostname: charmander.mewm.org
  environment:
    - NEW_RELIC_LICENSE_KEY=&lt;api key here&gt;
</code></pre>
<p>As you can see, it takes very few instructions to setup up the server monitoring. After booting the container, the <code>hostname</code> should pop up in the New Relic console.</p>
<h2 id="finalwords">Final words</h2>
<p>Monitoring your applications and servers, are crucial to businesses. Detecting bottlenecks and evaluate performance is much easier if you have proper monitoring set up. New Relic is just one of the many tools out there. Also, stats and infographics just turns me on!</p>
<p>I use New Relic because it's what I have most experience with, but there are a ton of alternatives out there.<br>
Also, back in the days when I signed up, they promised me a t-shirt - never got it though :(</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Setting up a Ghost blog and MariaDB with Docker and docker-compose]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><strong>UPDATE: Since i wrote this post, <a href="https://github.com/docker/compose">docker-compose</a> has been released by the docker team. This replaces fig completely, which is now deprecated. To make the transition, you just have to rename <code>fig.yml</code> to <code>docker-compose.yml</code> and use <code>$ docker-compose</code> instead of <code>$ fig</code><br>
Obviously, you need to <a href="https://docs.docker.com/compose/install/">install docker-compose</a> on the</strong></p>]]></description><link>https://blog.mewm.org/ghost-mariadb-with-docker-fig/</link><guid isPermaLink="false">5e4da2e40a5a2900013fe96d</guid><dc:creator><![CDATA[Dennis Micky Jensen]]></dc:creator><pubDate>Thu, 19 Feb 2015 23:49:26 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><strong>UPDATE: Since i wrote this post, <a href="https://github.com/docker/compose">docker-compose</a> has been released by the docker team. This replaces fig completely, which is now deprecated. To make the transition, you just have to rename <code>fig.yml</code> to <code>docker-compose.yml</code> and use <code>$ docker-compose</code> instead of <code>$ fig</code><br>
Obviously, you need to <a href="https://docs.docker.com/compose/install/">install docker-compose</a> on the host first.<br>
This now works with OSXContainerHost, if you're using OSX.</strong></p>
<p>I just recently set this blog ghost blog up, so I decided to write this post along with it. This post elaborates the setup which is currently hosted on Digital Ocean.</p>
<p>Ghost is a widely used blogging platform written entirely in javascript, both on the client and on the server using node and expressjs. By default, it uses a SQLite instance for persistence, but I've never really used nor liked SQLite that much, and also to fit an even better use-case for using Docker, while maintaining separation of concerns. So we're splitting up the containers by responsibility and using MariaDB as our &quot;favorite database&quot;!</p>
<p>We will split the responsibilities up in Docker containers which runs completely isolated from each other. One for the ghost platform, one for the database and one for data only. The data container will host all data, which will be accessible from within our containers as mounted volumes.<br>
And with a few small bash scripts, we will get the essentials bootstrapped and everything running.</p>
<p>Using Fig, we can easily manage our Docker containers and their respective builds. If you've never played around with Docker before, I would encourage you to go familiarize your self with <a href="https://docs.docker.com/userguide">it's documentation</a> before jumping in to fig.<br>
Fig provides a clean interface for managing containers, and lets you handle all your app's services from a single source.<br>
Fig also has a number of other really nice features, such as scaling, though I haven't tried it yet.</p>
<p><em>Disclaimer: I'm no docker expert whatsoever, nor do I claim that this is <strong>the way</strong> to do it, but just my 1337 cents</em></p>
<h2 id="toolsweregonnause">Tools we're gonna use</h2>
<ul>
<li><s><a href="http://www.fig.sh">Fig</a></s> - <a href="https://github.com/docker/compose">docker-compose</a> has been released, which replaces fig.</li>
<li><a href="https://www.docker.com">Docker</a> - <s>you might need <a href="http://boot2docker.io">boot2docker</a> if you're running OSX. <a href="https://github.com/SeerUK/OSXContainerHost">OSXContainerHost</a> is actually my favorite choice for proxying docker on OSX, <a href="https://github.com/SeerUK/OSXContainerHost/issues/2">but it has a known issue with the devicemapper when using fig.</a></s> The release of docker-compose has fixed the devicemapper issue, and now works perfectly.</li>
<li>Your favorite editor!</li>
</ul>
<h2 id="problem">Problem</h2>
<p>I want a Ghost blogging platform connected with MariaDB. I also want to be able to grab backups, and update my theme easily. Ohh, and I want that shit dockerized and managed with fig!</p>
<h2 id="objectives">Objectives</h2>
<p>So we have our quite abstract problem. Let's split it into smaller objectives:</p>
<ul>
<li><a href="#dataonlydocker">Create a Dockerfile for a data-only container</a></li>
<li><a href="#mariadbdockerfile">Create a Dockerfile for setting up MariaDB</a>
<ul>
<li><a href="#mariadbstartscript">Create a script to start the server</a></li>
<li><a href="#mariadbcreateuserscript">Create a one-time script for creating a default set of user credentials</a></li>
</ul>
</li>
<li><a href="#ghostdocker">Create a Dockerfile for setting up Ghost</a>
<ul>
<li><a href="#ghostconfig">Add our ghost config.js file</a></li>
<li><a href="#ghoststartscript">Create a script to checkout/update our theme and start the server</a></li>
</ul>
</li>
<li><a href="#fig">Compose a fig.yml to orchestrate all our app's services</a></li>
<li><a href="#fig">Manage the containers with Fig</a></li>
<li><a href="#backuprestorescripts">Optional: Create a bash scripts to create/restore backups</a></li>
<li><a href="#nginxvirtualhost">Optional: Setup a virtual host for nginx to proxy requests to our blog</a></li>
</ul>
<p><a id="dataonlydocker"></a></p>
<h3 id="dataonlydockerfile">Data-only Dockerfile</h3>
<pre><code class="language-php">FROM busybox
MAINTAINER Dennis Micky Jensen &lt;dj@miinto.com&gt;

# Create default ghost content dirs
RUN mkdir -p /var/www/ghost/content/apps
RUN mkdir -p /var/www/ghost/content/images
RUN mkdir -p /var/www/ghost/content/themes
RUN mkdir -p /var/www/ghost/content/data
</code></pre>
<p>Here we're instructing Docker to create a few default directories when building our image. The reason for creating these folders, is that the content folder will be mounted from the data container and might risk deleting the initial folders that came with the installation of ghost. If these folders doesn't exist, ghost wont run.<br>
Initially, I didn't event want to have a Dockerfile for this container (you can use either an image or a Dockerfile), but somehow without the Dockerfile, I could not get data to persist over restarts, so yeah, fuck that.<br>
The base image we're using here; <code>busybox</code>, is just a really small image, which is perfect for our data-only container. You can find already existing images on <a href="https://registry.hub.docker.com">Docker Hub</a></p>
<p><a id="mariadbdocker"></a></p>
<h3 id="mariadbdockerfile">MariaDB Dockerfile</h3>
<pre><code class="language-dockerfile">FROM ubuntu:trusty
MAINTAINER Dennis Micky Jensen &lt;root@mewm.org&gt;

# Download MariaDB
RUN apt-get update &amp;&amp; \
    apt-get install -y mariadb-server pwgen &amp;&amp; \
    rm -rf /var/lib/mysql/* &amp;&amp; \
    apt-get clean &amp;&amp; \
    rm -rf /var/lib/apt/lists/*

# Set bind address to 0.0.0.0 and enforce port
RUN sed -i -r 's/bind-address.*$/bind-address = 0.0.0.0/' /etc/mysql/my.cnf
RUN sed -i -r 's/port.*$/port = 3305'/ /etc/mysql/my.cnf

# Add bash scripts for creating a user and run server
ADD create-mariadb-user.sh /create-mariadb-user.sh
ADD run-mariadb.sh /run-mariadb.sh
RUN chmod 775 /*.sh

# To avoid mysql whining about this variable
ENV TERM dumb 

# Set default entry point
CMD [&quot;/run-mariadb.sh&quot;]
</code></pre>
<p>There are more fine and optimized base images for databases, than just ubuntu:trusty, but I went with a straight ubuntu for simplicity sake.<br>
The important thing to notice here, is opening up for connections outside localhost, and adding the two bash scripts we need. The containers will have there &quot;links to other containers&quot; defined in the <code>fig.yml</code> file. Finally, we're instructing the container to invoke <code>run-mariadb.sh</code> as the default command upon invocation.</p>
<p><a id="mariadbstartscript"></a></p>
<h4 id="mariadbstartscript">MariaDB start script</h4>
<pre><code class="language-bash">#!/bin/bash

VOLUME_HOME=&quot;/var/lib/mysql&quot;
if find ${VOLUME_HOME} -maxdepth 0 -empty | read v; then
    echo &quot; -&gt; Installation detected in $VOLUME_HOME&quot;
    echo &quot; -&gt; Installing MariaDB&quot;
    mysql_install_db &gt; /dev/null 2&gt;&amp;1
    echo &quot; -&gt; Done!&quot;
    /create-mariadb-admin-user.sh
else
    echo &quot;-&gt; Booting on existing volume!&quot;
fi

exec mysqld_safe
</code></pre>
<p>This script is the default command for our database container. When initial boot is detected, we bootstrap the server and invoke our create-user script outlined below, then we start our server.</p>
<p><a id="mariadbcreateuserscript"></a></p>
<h4 id="createdatabaseuserscript">Create database user script</h4>
<pre><code class="language-bash">#!/bin/bash
/usr/bin/mysqld_safe &gt; /dev/null 2&gt;&amp;1 &amp;

RET=1
while [[ RET -ne 0 ]]; do
    sleep 5
    mysql -uroot -e &quot;status&quot; &gt; /dev/null 2&gt;&amp;1
    RET=$?
done

mysql -uroot -e &quot;CREATE USER '$DEFAULT_USER'@'%' IDENTIFIED BY '$DEFAULT_PASS'&quot;
mysql -uroot -e &quot;GRANT ALL PRIVILEGES ON *.* TO '$DEFAULT_USER'@'%' WITH GRANT OPTION&quot;
mysql -uroot -e &quot;CREATE DATABASE ghost&quot;

mysqladmin -uroot shutdown
</code></pre>
<p>This script will be invoked from <code>run-mariadb.sh</code> when initial boot is detected. We start our database instance, waits until the instance is ready,<br>
then creating the user with credentials which we will define later in our <code>fig.yml</code>.</p>
<p><a id="ghostdocker"></a></p>
<h3 id="ghostdockerfile">Ghost Dockerfile</h3>
<pre><code>FROM node:0.10-wheezy
MAINTAINER Dennis Micky Jensen &quot;root@mewm.org&quot;

# Download and install latest version of ghost
RUN cd /tmp 
RUN wget https://ghost.org/zip/ghost-latest.zip 
RUN apt-get update
RUN apt-get install zip unzip 
RUN unzip ghost-latest.zip -d /ghost 
RUN rm -f ghost-latest.zip 
RUN mkdir -p /var/www
RUN mv /ghost /var/www 
RUN npm install sqlite3 --build-from-source
RUN cd /var/www/ghost &amp;&amp; npm install --production 

# Move ghost into the system neighbourhood. Welcome yo!
ENV HOME /var/www/ghost
RUN useradd ghost --home /var/www/ghost
WORKDIR /var/www/ghost

# Add config and script to start the engine
ADD config.js /var/www/ghost/config.js
ADD run-ghost.sh /run-ghost.sh
RUN chmod 0500 /run-ghost.sh

CMD /run-ghost.sh



</code></pre>
<p>When building the image from this Dockerfile, we download and install the latest version of ghost. We also create and configure a user which will run the ghost app.<br>
You might have noticed, that there is next to none environment variables set. They will be defined in <code>fig.yml</code> which we will get to later.<br>
You can basically decide your self, how wanna split the instructions between fig and the Dockerfile. I just went for a solution I thought was adequate, but frankly, I'm not quite sure about the best practices here though.</p>
<p><a id="ghostconfig"></a></p>
<h4 id="ghostconfigfile">Ghost config file</h4>
<p><a href="https://gist.github.com/mewm/778644a11b0f28670fe4">This gist</a> provides a quite generic template for <code>config.js</code>, that's more or less completely configurable with environment variables.<br>
To be honest, I don't remember where I got this from, so I don't know who to credit :(<br>
I have not considered emailing in this setup, but it's only a couple of environment variables you need to add, which you can spoof from the file.</p>
<p><a id="ghostbootscript"></a></p>
<h4 id="ghostbootscript">Ghost boot script</h4>
<pre><code>#!/bin/bash
_theme_source_destination=&quot;${HOME}/content/themes/casper&quot;

if [ -d ${_theme_source_destination} ]; then
    cd ${_theme_source_destination} &amp;&amp; git pull origin master
    cd $HOME
else
    git clone ${THEME_SOURCE} $HOME/content/themes/casper
fi

chown -R ghost /var/www/ghost
su ghost -c &quot;npm start&quot;
</code></pre>
<p>Here we are detecting if the theme (also configured in <code>fig.yml</code>) has been checked out from git yet, and if not, we pull the latest changes. This script runs every time you start the container, so if you've pushed changes to your theme, it's just a matter of restarting your container to get the updates.<br>
Then we ensure ghost ownership to our web folder, and start the express server. This might not be the most secure procedure, but it floats my boat for now :P</p>
<p><a id="fig"></a></p>
<h3 id="fig">Fig</h3>
<p>This is where we define our services for our whole application. Fig will take care of building images and starting containers.<br>
Here is how our <code>fig.yml</code> looks like:</p>
<pre><code class="language-yml">data:
  build: ./data
  volumes:
    - /var/lib/mysql
    - /var/www/ghost/content
#    - /Users/mewm/www/ghost-theme:/var/www/ghost/content/themes/casper This can be added for theme development. Comment out the theme stuff in run-ghost.sh before rebuilding
db:
  build: ./mariadb
  ports:
    - &quot;3305:3305&quot;
  volumes_from:
    - data
  environment:
    - DEFAULT_USER=ghost # A user with this name will be created
    - DEFAULT_PASS=foobarbaz
    - PORT=3305
web:
  build: ./ghost
  ports:
    - &quot;2368:2368&quot;
  links:
    - db:database
  volumes_from:
    - data
  environment:
    - DB_HOST=database
    - DB_CLIENT=mysql
    - DB_USER=ghost
    - DB_PASSWORD=foobarbaz
    - DB_PORT=3305
    - DB_DATABASE=ghost
    - NODE_ENV=production
    - URL=http://blog.mewm.org
    - THEME_SOURCE=https://github.com/mewm/ghost-theme # Git repo to fetch theme from

</code></pre>
<p>As you can see, configuring Docker containers with Fig is really easy. <a href="http://www.fig.sh/yml.html">There is fig counterpart to almost all options that goes with <code>docker run</code></a><br>
As vaguely mentioned before, you can define your instructions either in <code>fig.yml</code> or the <code>Dockerfile</code>, and mix it up that way, to whatever fits your use-case best.<br>
For each service, I have a sub folder containing its Dockerfile and related scripts. The <code>build</code> options specifies the path to the Dockerfile. The only mandatory option in the <code>fig.yml</code> is <code>build</code> or <code>image</code>. Using image, you even need a Dockerfile.<br>
Now we have structured the essentials for our application, we're ready to fire it up! A more complete cli reference can be found <a href="http://www.fig.sh/cli.html">here</a>.</p>
<pre><code class="language-bash"># Build application from our fig.yml 
$ fig build

# Start our application. This runs the CMD specified in the Dockerfiles
$ fig up

# If you've made changes to your theme, you can just restart the web service to update from github
$ fig restart web
</code></pre>
<p>An there you have it! Both commands aggregates a fair amount of output from each container, but hopefully you should see everything go pretty smoothly. Fig will stay open if no exit code is detected. You might wanna throw in a <code>-d</code> to run it &quot;Detached mode&quot;.</p>
<p>When you're playing around with builds, it's useful to remove containers you don't use anymore. The <code>rm</code> command removes all stopped containers. By specifying a service name, you can target specific services. You can start and stop existing containers with <code>start</code> and <code>stop</code>.<br>
It's worth mentioning that <code>up</code> doesn't rebuild images automatically, so if you've made changes to a Dockerfile, you will need to <code>build</code> it again. To get an overview of your containers, <code>ps</code> will do the job, just as with the docker cli. If your container has a shell (busybox doesn't) and you wanna sneak around inside your container, you can start an interactive shell with <code>fig run web /bin/bash</code> (currently, I'm experiencing an issue where this command actually just hangs. By waiting 5 seconds and then CTRL+C it actually continues).</p>
<p>A few caveats I've encountered, which is worth mentioning:</p>
<ul>
<li>Docker seems to give a shit about your low-volume overly expensive SSD disk, and tends to build up quite a few containers and images occupying a lot of space. Just try do a <code>docker ps -a</code> (shows all your containers), <code>docker images</code> (shows all images). They don't even have an easy way of cleaning it up, but luckily there is this little naughty one-line that does the job:  <code>docker rm $(docker ps -a -q) &amp;&amp; docker rmi $(docker images -q)</code> - Warning: all your shit will be lost. If you're on OSX, you can also just destroy your VM box that contains docker.</li>
<li>Maybe you've noticed, but the data-only container isn't actually running. That's because even though the container is stopped, the volumes are still active. This took me quite a while to figure out :P</li>
</ul>
<p><a id="backuprestorescripts"></a></p>
<h3 id="backupandrestorescripts">Backup and restore scripts</h3>
<p>This is where we take advantage of our mountable volumes on our data-only.container.</p>
<pre><code># Backup db data to a tar file
docker run --volumes-from ghostmariadbfig_data_1 -v $(pwd)/backups:/backups ubuntu tar cvf /backups/db_backup_$(date +%Y_%m_%d).tar /var/lib/mysql

# Restore database backup
docker run --volumes-from ghostmariadbfig_data_1 -v $(pwd)/backups:/backups ubuntu tar xvf /backups/db_backup_&lt;date of backup&gt;.tar


# Backup ghost content data to tar file
docker run --volumes-from ghostmariadbfig_data_1 -v $(pwd)/backups:/backups ubuntu tar cvf /backups/ghost_backup_$(date +%Y_%m_%d).tar /var/www/ghost/content
 
# Restore ghost content backup
docker run --volumes-from ghostmariadbfig_data_1 -v $(pwd)/backups:/backups ubuntu tar xvf /backups/ghost_backup_&lt;date of backup&gt;.tar
</code></pre>
<p>Here we mount the volumes from our data container, and also mount a host directory to a backup folder inside the container. Then we create a tar file from our mounted data volume and archives it in the mounted host folder.<br>
The name <code>ghostmariadbfig_data_1</code> is just the default name fig gave our data-only container. You can spoof the name of your containers with <code>fig ps</code>.<br>
This might look pretty wicked, but if you chunk them down to bits, it's easier to wrap your head around it. Here is what happens:</p>
<ul>
<li><code>docker run</code> - command to run a container</li>
<li><code>--volumes-from ghostmariadbfig_data_1</code> - Mounts the volumes from our data container so they are accessible inside our temporary ubuntu container.</li>
<li><code>-v $(pwd)/backups:/backups</code> - Mounts our ./backups as /backups inside our container</li>
<li><code>ubuntu</code> - The image we wish to template our container. This will be downloaded automatically if not found locally.</li>
<li><code>tar cvf /backups/ghost_backup_$(date +%Y_%m_%d).tar /var/www/ghost/content</code> - This is the command sequence to run once the container is booted. We create a tar from our wanted data and saves named todays date. When the operation is done and docker receives an exit code, the container will shut down automatically.</li>
</ul>
<p>To restore each backup, all you have to do, is extract the tar file instead of creating it. Remember to change the file name :P<br>
It's fairly easy to rewrite these snippets to grab the tar filename from a command line argument, <a href="https://github.com/mewm/ghost-mariadb-docker/tree/01-setting-up-ghost-blog">just take a look at this project on github</a></p>
<p><a id="nginxvirtualhost"></a></p>
<h3 id="nginxvirtualhost">Nginx virtual host</h3>
<p>If you like me is a sucker for nginx, and you host several sites on your server already (which are likely occupying port 80), you can use a virtual host to proxy the requests to your ghost app. There is similar script out there for apache as well.</p>
<pre><code>server {
   listen 0.0.0.0:80;
   server_name http://blog.mewm.org; #replace this line with your domain
   access_log /var/log/nginx/blog.mewm.org.log; #replace this with any log name
 
   location / {
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header HOST $http_host;
       proxy_set_header X-NginX-Proxy true;
       proxy_pass http://127.0.0.1:2368;
       proxy_redirect off;
   }
 }
</code></pre>
<h2 id="finalwords">Final words</h2>
<p>All the code outlined can be found in a diversed branch on <a href="https://github.com/mewm/ghost-mariadb-docker/tree/01-setting-up-ghost-blog">github</a>. The <code>master</code> branch contains the newest version of the application setup.<br>
I think Docker and fig are amazing tools and I use them as much as possible. Getting your application up and running is a blaze, and if your worried about any performance overhead in your production environments, check this <a href="http://stackoverflow.com/questions/21889053/what-is-the-runtime-performance-cost-of-a-docker-container">SO post</a>. It shows very little overhead, which even in the short run is hugely compensated for in flexibility.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>