<?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>gj |</title>
	<atom:link href="https://blog.gaiterjones.com/category/docker/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.gaiterjones.com/category/docker/</link>
	<description>gaiterjones</description>
	<lastBuildDate>Wed, 10 Feb 2021 10:03:59 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8</generator>
	<item>
		<title>GMAIL TLS Negotiation failed, the certificate doesn&#8217;t match the host</title>
		<link>https://blog.gaiterjones.com/gmail-tls-negotiation-failed-the-certificate-doesnt-match-the-host/</link>
					<comments>https://blog.gaiterjones.com/gmail-tls-negotiation-failed-the-certificate-doesnt-match-the-host/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Thu, 16 Apr 2020 15:46:43 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[Google Gmail]]></category>
		<guid isPermaLink="false">https://blog.gaiterjones.com/?p=2152</guid>

					<description><![CDATA[Gmail lets you Send emails from a different email address or alias so that If you use other email addresses or providers, you can send email from that address via...<a class="more-link" href="https://blog.gaiterjones.com/gmail-tls-negotiation-failed-the-certificate-doesnt-match-the-host/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>Gmail lets you Send emails from a different email address or alias so that If you use other email addresses or providers, you can send email from that address via Gmail.</p>
<p>To do this you configure an alias account in Gmail settings configured with the credentials of your mail service. This is useful if you want to consolidate email accounts or if you have a private email server and want to use Gmail to send email via this server using your various private email address domains.</p>
<p>At the start of April 2020 Google rolled out a security update that affected mail delivery using third party accounts. All emails sent via the alias account would not deliver, bouncing back with the error <em>TLS Negotiation failed, the certificate doesn&#8217;t match the host.</em></p>
<h1>TLS Negotiation failed, the certificate doesn&#8217;t match the host.</h1>
<p>Google appears to be enforcing a new email encryption policy for secureTLS connections including validating that the host name on the mail server TLS certificate matches the canonical hostname (MX record) of the third party mail account.</p>
<p>If the host name does not match you can no longer use an encrypted TLS connection in Gmail to send email via your (or your ISP&#8217;s) mail servers.</p>
<p>For example, if your MX record resolves to <em>mail.domain.com</em> but the TLS certificate presented is for <em>smtp.domain.com</em> then Gmail will not connect to your mail server. For some users the only option to get mail working again is to revert to an unencrypted connection &#8211; strange that Google even allow that!</p>
<p><span>Google have updated the help article for </span><a href="https://support.google.com/mail/answer/22370" rel="nofollow noopener noreferrer" target="_blank">Send emails from a different address or alias</a><span> to include a section about this problem.</span></p>
<p><strong>Google also no longer accept self signed certificates for TLS mail connections.</strong></p>
<p>I use an EXIM4 docker container for my private mail relay, and use Gmail as the hub for my email send/receive. To workaround this problem I created a docker Certbot container and issued new LetsEncrypt TLS certificates for all my private mail domains used with Gmail as well as the primary TLS certificate for my Mail server.</p>
<p>I can confirm this resolves the problem and third party provider email sending via Gmail is now working again.</p>
<p>For anyone using Exim4 the way to configure Exim to use multiple TLS certificates is to dynamically match them to your mail domain, I did this using</p>
<p>tls_privatekey=${if exists{/etc/exim4/tls/exim.key.${tls_sni}}{/etc/exim4/tls/exim.key.${tls_sni}}{/etc/exim4/tls/exim.key.mail.defaultdomain.com}}<br />
tls_certificate=${if exists{/etc/exim4/tls/exim.crt.${tls_sni}}{/etc/exim4/tls/exim.crt.${tls_sni}}{/etc/exim4/tls/exim.crt.mail.defaultdomain.com}}</p>
<p><a href="https://support.google.com/mail/thread/38336515?hl=en">Thousands of people</a> have been affected by this. Considering the amount of people working from home or struggling to work at all during the Corona Virus pandemic its really bad timing by Google to implement new email security policies that are service affecting for a lot of users.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/gmail-tls-negotiation-failed-the-certificate-doesnt-match-the-host/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Magento 2.2.X Development and Upgrades</title>
		<link>https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/</link>
					<comments>https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Thu, 03 May 2018 08:55:14 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[magento2]]></category>
		<category><![CDATA[upgrade]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1883</guid>

					<description><![CDATA[Today (2nd May 2018) Magento released Magento CE 2.2.4. Recently the Magento Devs have been pretty busy pushing out 2.2.x updates and Magento 2 is maturing nicely. I am still...<a class="more-link" href="https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>Today (2nd May 2018) Magento released Magento CE 2.2.4. Recently the Magento Devs have been pretty busy pushing out 2.2.x updates and Magento 2 is maturing nicely. I am still getting to grips with Magento 2 and don&#8217;t expect to release a live site for at least another year so it makes sense to develop with the latest version of Magento. My <a href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/">Magento 2.2.x development environment</a> is built on Docker and installing new Magento 2 dev shops is a breeze:</p>
<ol>
<li>git clone https://github.com/gaiterjones/docker-magento2-2</li>
<li>cd docker-magento2-2/magento</li>
<li>edit .env</li>
<li>docker-compose build</li>
<li>docker-compose up -d</li>
<li>http://magento2.dev.com</li>
</ol>
<p>Upgrading Magento is always a scary experience &#8211; Magento 2 is even more terrifying so I recommend you get used to doing updates with your dev systems. If you are manually upgrading from a previous 2.x version, you can use composer within the docker container:</p>
<ol>
<li>Take a backup</li>
<li>Enter maintenance mode</li>
<li>edit compose.json
<ol>
<li>change version</li>
</ol>
</li>
<li>flush redis
<ol>
<li><span>redis-cli flushall in the redis containers</span></li>
</ol>
</li>
<li>composer update</li>
<li><span>rm -rf var/cache/* var/page_cache/* var/generation/* var/di/*</span></li>
<li><span>chmod +x bin/magento</span></li>
<li><span>php bin/magento cache:flush</span></li>
<li><span>php bin/magento setup:upgrade</span></li>
<li><span>php bin/magento indexer:reindex</span></li>
</ol>
<p>If the upgrade breaks any sample data reinstall with php -f bin/magento sampledata:deploy</p>
<p>I regularly update my Magento 2 docker containers with each version update check them out at <a href="https://github.com/gaiterjones/docker-magento2-2">https://github.com/gaiterjones/docker-magento2-2</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/magento-2-2-x-development-and-upgrades/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Simulate and test your Alexa Skill with the Alexa Skills Kit Command Line Interface (ASK CLI)</title>
		<link>https://blog.gaiterjones.com/simulate-and-test-your-alexa-skill-with-the-alexa-skills-kit-command-line-interface-ask-cli/</link>
					<comments>https://blog.gaiterjones.com/simulate-and-test-your-alexa-skill-with-the-alexa-skills-kit-command-line-interface-ask-cli/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Wed, 25 Apr 2018 10:16:31 +0000</pubDate>
				<category><![CDATA[Alexa]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[alexa]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1871</guid>

					<description><![CDATA[The new Alexa Skills Kit Developer Console is fab and a lot of things have changed since I developed my first skill in 2016, one of the changes is skill...<a class="more-link" href="https://blog.gaiterjones.com/simulate-and-test-your-alexa-skill-with-the-alexa-skills-kit-command-line-interface-ask-cli/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>The new Alexa Skills Kit Developer Console is fab and a lot of things have changed since I <a href="https://blog.gaiterjones.com/amazon-alexa-php-hello-world-example/">developed my first skill in 2016</a>, one of the changes is skill testing which you can now do quite easily with the Alexa Skills Kit Command Line Interface (ASK CLI)</p>
<p>If you are building skills with my PHP code here are a few notes on using the ASK CLI to do simple skill invocation tests using a Docker compose ASK CLI nodejs container.</p>
<p>Assuming you are familiar with using Docker and docker-compose here are the steps to testing your skill from the command line :</p>
<ol>
<li>git clone https://github.com/gaiterjones/docker-amazon-ask-cli</li>
<li>cd docker-amazon-ask-cli</li>
<li>docker-compose build</li>
<li>docker-compose up -d</li>
<li>./init.sh
<ol>
<li>Initialise <em>ask</em> with your amazon developer credentials, you will be prompted to create a default profile and then to paste an authorisation url into your browser. The url will take you to an Amazon authorisation page where you need to login with your developer login. You will then receive an authorisation code which you can paste into the init window to create your cli-config credentials file.</li>
<li><img fetchpriority="high" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2018/04/amazon-ask-cli-1.jpg" alt="" width="600" height="194" class="aligncenter size-full wp-image-1872" /></li>
</ol>
</li>
<li>Test skill with skill simulation
<ol>
<li>./ask.sh amzn1.ask.skill.123 &#8220;ask my skill to do something&#8221; where amzn1.ask.skill.123 is the id of your skill and &#8220;ask my skill to do something&#8221; is the invocation term you want to test with your skill &#8211; i.e. what you would ask Alexa to do to open and use your skill.</li>
<li><img decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2018/04/amazon-ask-cli-2.jpg" alt="" width="600" height="265" class="aligncenter size-full wp-image-1873" /></li>
</ol>
</li>
</ol>
<p>Check out <em>ask.sh</em> for the ASK CLI syntax being used. You can use this directly from the container with <em>docker exec -it dockeramazonaskcli_nodejs_1 /bin/bash</em></p>
<p>The credentials will be saved in <em>cli-config</em> when the container is stopped.</p>
<p>You can do a whole lot more with the ASK CLI, check out the documentation here <a href="https://developer.amazon.com/docs/smapi/ask-cli-command-reference.html">https://developer.amazon.com/docs/smapi/ask-cli-command-reference.html</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/simulate-and-test-your-alexa-skill-with-the-alexa-skills-kit-command-line-interface-ask-cli/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Deploy OpenFaaS Serverless PHP Functions</title>
		<link>https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/</link>
					<comments>https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Mon, 20 Nov 2017 15:29:57 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Open FaaS]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[openfaas]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1779</guid>

					<description><![CDATA[If you follow Alex Ellis on Twitter one acronym that you will have been seeing a lot in your Twitter feed lately is FaaS. Alex is a pretty smart chappy...<a class="more-link" href="https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>If you follow <a href="https://blog.alexellis.io/">Alex Ellis</a> on <a href="https://twitter.com/alexellisuk">Twitter</a> one acronym that you will have been seeing a lot in your Twitter feed lately is <strong>FaaS</strong>. Alex is a pretty smart chappy who does a lot of cool stuff with Docker, Amazon Alexa and his <a href="https://blog.alexellis.io/iot-growbox/">Raspberry Pi</a>. This year he has been developing <a href="https://www.openfaas.com/"><strong>OpenFaaS</strong></a> an open source <em>functions as a service</em> framework.</p>
<h1>What is OpenFaaS?</h1>
<p>OpenFaaS lets you build and distribute &#8220;serverless&#8221; functions in a cloud computing environment. The &#8220;function&#8221; could be simple application logic that you program &#8211; or execution of a binary to perform an action. The term serverless is a slight misnomer as you still require a server, or indeed many servers, but by deploying your function into the cloud you don&#8217;t have to worry about scaling or managing physical server resources yourself &#8211; which is pretty cool.</p>
<p>OpenFaaS works by packaging your function up into a docker container customised to work with OpenFaaS. The OpenFaaS framework stack handles the creation and deployment of the container allowing you to execute your function with a simple command line or http request.</p>
<p>OpenFaaS doesn&#8217;t really care how you create your function as long as the container behaves in the way the framework and the <em>function watchdog</em> expects. This means whilst OpenFaaS ships with support for languages like Python and NODE.js it should work with just about anything you throw at it which means you can package up just about anything as a serverless function.</p>
<p>I&#8217;m developing with good old PHP so the first thing I did when I decided to take a closer look at OpenFaaS was to google &#8220;open faas php&#8221; to see how I could create serverless functions written in PHP. My search led me to a php template for OpenFaaS developed by <a href="https://github.com/itscaro/openfaas-template-php">Minh-Quan Tran</a>. The template tells OpenFaaS how to build PHP5 or PHP7 containers to run your PHP code as OpenFaaS functions. After trying out the template there were a couple of issues with it I wanted to address, so I forked it and made a few changes. </p>
<p>If you want to deploy OpenFaaS PHP functions here&#8217;s a step by step guide that will get you from Zero to Hero in just a few minutes.</p>
<h1>Install the OpenFaaS Stack and CLI</h1>
<p>Assuming you already have Docker installed, the first thing you need to do is initialise a Docker swarm and deploy the OpenFaaS stack.</p>
<pre class="brush: bash; title: ; notranslate">
docker swarm init --advertise-addr $(hostname -i)
</pre>
<p>Change into a suitable working folder and install the OpenFaaS stack by cloning it from github and executing the deploy script.</p>
<pre class="brush: bash; title: ; notranslate">
git clone https://github.com/openfaas/faas &amp;&amp; \
  cd faas &amp;&amp; \
  ./deploy_stack.sh
</pre>
<p>Test that the stack is working by invoking the echoit example function that echoes back any input data you send it.</p>
<pre class="brush: bash; title: ; notranslate">
curl 127.0.0.1:8080/function/func_echoit -d 'hello world'
</pre>
<p>Now that OpenFaaS is working you need to install the OpenFaaS cli framework (faas-cli) that allows you to build, deploy and invoke your own functions easily from the command line.</p>
<pre class="brush: bash; title: ; notranslate">
curl -sL https://cli.openfaas.com | sudo sh
</pre>
<p>Next install the OpenFaaS PHP template</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli template pull https://github.com/gaiterjones/openfaas-template-php
</pre>
<pre>
2017/11/19 09:52:30 Attempting to expand templates from master.zip
2017/11/19 09:52:30 Fetched 2 template(s) :  from https://github.com/gaiterjones/openfaas-template-php
2017/11/19 09:52:30 Cleaning up zip file...
</pre>
<h1>Build and Deploy a PHP OpenFaaS function</h1>
<p>Once the template is installed we can test it by creating our first PHP function. The OpenFaaS command line syntax for creating a new function is <strong>faas-cli new <em>functionname</em> &#8211;lang <em>languagename</em></strong>. The PHP template uses the language name <em>php</em> for PHP7 functions and <em>php5</em> for PHP5 functions. We will create a PHP7 function called func_php1 using the code in the template.</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli new func_php1 --lang php
</pre>
<pre>
Folder: func_php1 created.
  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|


Function created in folder: func_php1
Stack file written: func_php1.yml
</pre>
<p>You will notice a new stack file func_php1.yml and function folder is created. For my tests using an Ubuntu virtual machine I had to edit func_php1.yml and change the hostname localhost to 127.0.0.1 as shown below.</p>
<pre>
provider:
  name: faas
  gateway: http://127.0.0.1:8080

functions:
  func_php1:
    lang: php
    handler: ./func_php1
    image: func_php1
</pre>
<p>In the func_php1 folder you will see three files</p>
<p> composer.json<br />
 Handler.php<br />
 php-extension.sh</p>
<p><code>Handler.php</code> contains the entrypoint for our OpenFaaS PHP function and looks like this</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

class Handler
{
    public function handle(string $_data): void {
        $_version = phpversion();
        echo 'PHP Version : '. $_version .&quot;\n&quot;. 'Data : '. $_data. &quot;\n\n&quot;;
    }
}
</pre>
<p>You can see the PHP method <code>Handler::handle()</code> is going to echo the PHP version, and whatever data is supplied to it from STDIN.</p>
<p>Build the service container for the function with</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli build -f func_php1.yml
</pre>
<p>Once the container has been built deploy it with</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli deploy -f func_php1.yml
</pre>
<pre>
Deploying: func_php1.
No existing function to remove
Deployed.
URL: http://127.0.0.1:8080/function/func_php1

200 OK
</pre>
<p>And that&#8217;s it, our PHP OpenFaaS function is ready to test we can invoke it from faas-cli</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli invoke -f func_php1.yml func_php1
</pre>
<p>Or use curl</p>
<pre class="brush: bash; title: ; notranslate">
curl 127.0.0.1:8080/function/func_php1 -d 'hello world'
</pre>
<pre>
PHP Version : 7.1.11
Data : hello world
</pre>
<p>You can also access all functions via the nifty OpenFaaS UI at http://yourhost/:8080/ui/</p>
<h1>Build and Deploy a GEO IP OpenFaaS PHP function</h1>
<p>Now let&#8217;s deploy a function with a little more functionality&#8230;</p>
<p>One API I use a lot is <a href="https://github.com/maxmind/GeoIP2-php" rel="noopener" target="_blank">GEOIP2 by MaxMind</a> it&#8217;s very useful for getting geographic data from an IP address. So let&#8217;s build an OpenFaaS PHP function to do just that.</p>
<p>Create a new PHP7 function called func_geoip</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli new func_geoip --lang php
</pre>
<p>Before building the function we need to add our PHP code and dependencies. First let&#8217;s add the PHP dependencies to the functions composer file by editing <em>func_geoip/composer.json</em></p>
<pre class="brush: plain; title: ; notranslate">
{
    &quot;name&quot;: &quot;function-php7&quot;,
    &quot;description&quot;: &quot;OpenFaaS GEOIP PHP function&quot;,
    &quot;type&quot;: &quot;project&quot;,
    &quot;license&quot;: &quot;MIT&quot;,
    &quot;require&quot;: {
        &quot;php&quot;: &quot;^7.0&quot;,
        &quot;maxmind-db/reader&quot;: &quot;~1.0&quot;,
        &quot;geoip2/geoip2&quot;: &quot;~2.0&quot;
    }
}
</pre>
<p>The geo ip data is read from a free <a href="http://dev.maxmind.com/geoip/geoip2/geolite2/">GEOLITE2 database</a> so we need to make that database available to our function. We can add data to our container using the <em>func_geoip/php-extension.sh</em> shell file which is executed when we build the template container.</p>
<pre class="brush: bash; title: ; notranslate">
echo &quot;Installing function dependencies&quot;
cd /usr/local/faas/function
curl -o GeoLite2-City.tar.gz http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz
tar -xvzf GeoLite2-City.tar.gz --strip 1
</pre>
<p>Now add the geo ip lookup code to our PHP Handler class by editing <code>func_geoip/Handler.php</code></p>
<span class="collapseomatic collapse" id="id6812227347959"  tabindex="0" title="Handler.php"    >Handler.php</span><div id="target-id6812227347959" class="collapseomatic_content ">
[php]
&lt;?php<br />
use GeoIp2\Database\Reader;</p>
<p>class Handler<br />
{<br />
    public function handle(string $_data): void {</p>
<p>        echo json_encode($this-&gt;geoIPLookup($_data));</p>
<p>    }</p>
<p>    protected function geoIPLookup($_ip)<br />
	{<br />
		$_reader = new Reader(&#8216;/usr/local/faas/function/GeoLite2-City.mmdb&#8217;);</p>
<p>			try // &amp; get geoip info<br />
			{<br />
				$_record = $_reader-&gt;city($_ip);</p>
<p>				$_geoIPData=array(<br />
					&#8216;ip&#8217; =&gt; $_ip,<br />
					&#8216;country&#8217; =&gt; $_record-&gt;country-&gt;name,<br />
					&#8216;isocode&#8217; =&gt; $_record-&gt;country-&gt;isoCode,<br />
					&#8216;region&#8217; =&gt; $_record-&gt;mostSpecificSubdivision-&gt;name,<br />
					&#8216;city&#8217; =&gt; $_record-&gt;city-&gt;name,<br />
					&#8216;postcode&#8217; =&gt; $_record-&gt;postal-&gt;code,<br />
					&#8216;latitude&#8217; =&gt; $_record-&gt;location-&gt;latitude,<br />
					&#8216;longitude&#8217; =&gt; $_record-&gt;location-&gt;longitude,<br />
					&#8216;googlemap&#8217; =&gt; &#8216;https://maps.google.com/?q=&#8217;. $_record-&gt;location-&gt;latitude. &#8216;,&#8217;. $_record-&gt;location-&gt;longitude<br />
				);<br />
			}<br />
			catch (\Exception $e)<br />
			{<br />
				$_geoIPData=array(<br />
					&#8216;ip&#8217; =&gt; $_ip,<br />
					&#8216;country&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;isocode&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;region&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;city&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;postcode&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;latitude&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;longitude&#8217; =&gt; &#8216;Not Found&#8217;,<br />
					&#8216;googlemap&#8217; =&gt; &#8216;Not Found&#8217;,<br />
                    &#8216;exception&#8217; =&gt; $e-&gt;getMessage()<br />
				);<br />
			}</p>
<p>		unset($_reader);</p>
<p>		return ($_geoIPData);</p>
<p>	}<br />
}<br />
[/php]
</div>
<p>Build and deploy the function</p>
<pre class="brush: bash; title: ; notranslate">
faas-cli build -f func_geoip.yml
faas-cli deploy -f func_geoip.yml
</pre>
<p>Now we can test it with</p>
<pre class="brush: bash; title: ; notranslate">
curl 127.0.0.1:8080/function/func_geoip -d '128.101.101.101'
</pre>
<p>The function returns the JSON formatted array of Geo data for the requested IP address</p>
<pre>
{"ip":"128.101.101.101","country":"United States","isocode":"US","region":"Minnesota","city":"Minneapolis","postcode":"55414","latitude":44.9759,"longitude":-93.2166,"googlemap":"https:\/\/maps.google.com\/?q=44.9759,-93.2166"}
</pre>
<h1>FaaS in Production</h1>
<p>We can easily access function data from other PHP applications using php curl to post the input data and return the output array. In production you need to consider how you will secure access to the function using some form of frontend proxy authentication.</p>
<p>Whether you will deploy simple php code as serverless functions in this way depends very much on the type of applications you are developing and the infrastructure available to you. I can<br />
 certainly think of a lot of my commonly used PHP library functions and classes that would become very useful deployed as OpenFaaS serverless functions.</p>
<h1>References</h1>
<ul>
<li><a href="https://www.openfaas.com/" rel="noopener" target="_blank">OpenFaaS</a></li>
<li><a href="https://github.com/openfaas/faas/blob/master/community.md" rel="noopener" target="_blank">OpenFaaS Community</a></li>
<li><a href="https://blog.alexellis.io/quickstart-openfaas-cli/" rel="noopener" target="_blank">OpenFaaS CLI</a></li>
<li><a href="https://github.com/gaiterjones/openfaas-template-php" rel="noopener" target="_blank">PHP Template</a></li>
<li><a href="https://docs.docker.com/engine/swarm/swarm-tutorial/" rel="noopener" target="_blank">Docker Swarm Tutorial</a></li>
</ul>
<h1>Tested on</h1>
<ul>
<li>Ubuntu Server 17.10</li>
<li>Docker 17.09.0-ce</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/how-to-deploy-open-faas-serverless-php-functions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Magento 2 theme blank SASS parent and child setup and installation</title>
		<link>https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/</link>
					<comments>https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Mon, 03 Jul 2017 13:04:59 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Frontend Development]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[less]]></category>
		<category><![CDATA[magento2]]></category>
		<category><![CDATA[sass]]></category>
		<category><![CDATA[theme blank sass]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1712</guid>

					<description><![CDATA[With CE 1.9 Magento introduced the SASS stylesheet language to aid frontend development. With Magento 2.x for reasons best known to the developers they switched from SASS to LESS. At the...<a class="more-link" href="https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>With CE 1.9 Magento introduced the <a href="http://sass-lang.com/">SASS</a> stylesheet language to aid frontend development. With Magento 2.x for <a href="https://magento.stackexchange.com/questions/26439/sass-in-1-9-less-in-2-why">reasons best known to the developers</a> they switched from SASS to LESS. At the end of the day both LESS and SASS are compiled into good old CSS but if your stylesheet language of preference is SASS or you are new to Magento and are looking for a good starting block to build a new theme from then it is well worth taking a look at <em>SnowDogApps </em><a href="https://github.com/SnowdogApps/magento2-theme-blank-sass">theme blank sass project</a>.</p>
<p>The <a href="https://community.magento.com/t5/Less-to-Sass-Community-Project/bd-p/less-to-sass">Less to Sass Community Project</a> is officially supported by Magento and Theme Blank SASS is the result of this project &#8211; a (production ready) Magento 2 blank theme converted to SASS.</p>
<p>Together with the accompanying <a href="https://github.com/SnowdogApps/magento2-frontools">Fronttools pack</a> you get the development tools and extendable SASS based blank theme you need to get you started building your own custom theme.</p>
<h1>Why use theme blank SASS ?</h1>
<ul>
<li>If you are coming from Magento 1.9 then you already are familiar with SASS</li>
<li>Magento 2.x may possibly move to SASS in the future</li>
<li>LUMA is not designed to be extended as a blank theme</li>
<li>Essential development tools such as browsersync are included</li>
</ul>
<h1>How to install theme blank SASS parent theme and Fronttools</h1>
<p>You can be up and running with theme blank SASS and fronttools in a few minutes. Here is a step by step theme blank sass and frontools installation guide tested on my <a href="https://github.com/gaiterjones/docker-magento2">Magento 2.x docker containers.</a></p>
<p>I am installing the parent theme and fronttools directly into my docker Magento 2 php-apache container with a bash script :</p>
<p><code>curl -o- http://gaiterjones.com/dropbox/magento2/theme-blank-sass/install-theme-blank-sass.sh | bash</code><br />
&nbsp;<br />
<span class="collapseomatic collapse" id="id681222734890a"  tabindex="0" title="script to install theme-blank-sass and fronttools"    >script to install theme-blank-sass and fronttools</span><div id="target-id681222734890a" class="collapseomatic_content ">
[bash]
#!/bin/bash<br />
# GAITERJONES<br />
# blog.gaiterjones.com<br />
# script to install theme-blank-sass and fronttools<br />
# for docker service https://github.com/gaiterjones/docker-magento2<br />
#<br />
set -e<br />
# variables<br />
RED=&#8217;&#92;&#48;33[0;31m&#8217;<br />
NC=&#8217;&#92;&#48;33[0m&#8217;</p>
<p># CHANGE THIS<br />
MAGENTO_DIR=&#8217;/var/www/dev/magento2&#8242;<br />
NVM_HOME=&#8217;/var/www&#8217;</p>
<p># start<br />
printf &quot;${RED}Installing theme-blank-sass into Magento Root: ${MAGENTO_DIR}&#8230;\n\n${NC}&quot;<br />
cd ${MAGENTO_DIR}<br />
composer require snowdog/theme-blank-sass<br />
composer require snowdog/frontools<br />
${MAGENTO_DIR}/bin/magento setup:upgrade<br />
${MAGENTO_DIR}/bin/magento cache:clean</p>
<p>printf &quot;${RED}Installing nvm&#8230;\n${NC}&quot;<br />
cd /tmp<br />
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash<br />
export NVM_DIR=${NVM_HOME}/.nvm<br />
 [ -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;&amp; \. &quot;$NVM_DIR/nvm.sh&quot;<br />
nvm install &#8211;lts<br />
nvm use &#8211;lts<br />
printf &quot;${RED}Installing gulp&#8230;\n${NC}&quot;<br />
npm install -g gulp-cli</p>
<p>printf &quot;${RED}Installing frontools&#8230;\n${NC}&quot;<br />
cd ${MAGENTO_DIR}/vendor/snowdog/frontools<br />
npm install<br />
gulp setup<br />
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/browser-sync.json<br />
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/themes-blank-sass-parent.json<br />
curl -o &quot;${MAGENTO_DIR}/vendor/snowdog/theme-blank-sass/web/images/logo.svg&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/logo-theme-blank-sass.svg</p>
<p>printf &quot;${RED}Generating theme-blank-sass styles&#8230;\n${NC}&quot;<br />
gulp styles</p>
<p>printf &quot;${RED}Configuring Snowdog/blank theme.\n${NC}&quot;<br />
THEME_ID=&quot;$(n98-magerun2.phar dev:theme:list &#8211;format=csv \<br />
  | grep &#8216;Snowdog/blank&#8217; | cut -d, -f1)&quot; \<br />
  ; test -n &quot;${THEME_ID}&quot; \<br />
  &amp;&amp; n98-magerun2.phar config:set design/theme/theme_id &quot;${THEME_ID}&quot;<br />
${MAGENTO_DIR}/bin/magento cache:clean</p>
<p># done<br />
printf &quot;${RED}Installation complete.\n\n${NC}&quot;<br />
[/bash]
</div>
<p>Here are the script commands broken down into some more detail :</p>
<p>Set the install environment variables</p>
<pre class="brush: bash; title: ; notranslate">
cd ${MAGENTO_DIR}
MAGENTO_DIR='/var/www/dev/magento2'
NVM_HOME='/var/www'
</pre>
<p><em>MAGENTO_DIR</em> is the path to the magento root and <em>NVM_HOME</em> the path to the NVM installation home folder &#8211; this is the home folder for the user that installs NVM</p>
<p>Install the theme and tools with composer, upgrade Magento and refresh caches.</p>
<pre class="brush: bash; title: ; notranslate">
composer require snowdog/theme-blank-sassinstall theme blank sass
composer require snowdog/frontoolsinstall fronttools

${MAGENTO_DIR}/bin/magento setup:upgradeupdate Magento
${MAGENTO_DIR}/bin/magento cache:cleanrefresh caches
</pre>
<p>Install NVM and gulp-cli</p>
<pre class="brush: bash; title: ; notranslate">
cd /tmp
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash
export NVM_DIR=${NVM_HOME}/.nvm
 &#x5B; -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;&amp; \. &quot;$NVM_DIR/nvm.sh&quot;
nvm install --lts
nvm use --lts
npm install -g gulp-cli
</pre>
<p>Install frontools.</p>
<pre class="brush: bash; title: ; notranslate">
cd ${MAGENTO_DIR}/vendor/snowdog/frontools
npm install
</pre>
<p>You run the fronttools setup with <em>gulp setup</em>, this will copy the project sample configuration files to ${MAGENTO_DIR}/dev/tools/frontools/config/.  You must edit <em>themes.json</em>, for the parent theme.</p>
<pre class="brush: plain; title: ; notranslate">
{
  &quot;blank&quot;: {
    &quot;src&quot;: &quot;vendor/snowdog/theme-blank-sass&quot;,
    &quot;dest&quot;: &quot;pub/static/frontend/Snowdog/blank&quot;,
    &quot;locale&quot;: &#x5B;&quot;en_GB&quot;],
    &quot;postcss&quot;: &#x5B;&quot;plugins.autoprefixer()&quot;],
    &quot;ignore&quot;: &#x5B;&quot;.test&quot;]
  }
}

</pre>
<p>The script is copying my themes and browser-sync json configuration files via curl.</p>
<pre class="brush: bash; title: ; notranslate">
gulp setup
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/browser-sync.json
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; http://gaiterjones.com/dropbox/magento2/theme-blank-sass/themes-blank-sass-parent.json
gulp styles
</pre>
<p>Next I compile the SASS to CSS and install it using</p>
<pre class="brush: bash; title: ; notranslate">
gulp styles
</pre>
<p>Finally I am using <a href="https://github.com/netz98/n98-magerun2">n98-magerun2</a> to enable the new theme, and refresh the Magento caches.</p>
<pre class="brush: bash; title: ; notranslate">
THEME_ID=&quot;$(n98-magerun2.phar dev:theme:list --format=csv \
  | grep 'Snowdog/blank' | cut -d, -f1)&quot; \
  ; test -n &quot;${THEME_ID}&quot; \
  &amp;&amp; n98-magerun2.phar config:set design/theme/theme_id &quot;${THEME_ID}&quot;
${MAGENTO_DIR}/bin/magento cache:clean
</pre>
<p><img decoding="async" src="http://gaiterjones.com/dropbox/magento2/theme-blank-sass/logo-theme-blank-sass.svg" width="248" height="73" class="aligncenter size-large" /><br />
Theme blank SASS parent theme is now installed. You can watch the install process below.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-install-magento-sass-blank-parent.gif" alt="magento 2 theme blank sass install video" class="aligncenter" /></p>
<p>We used the <em>gulp setup</em>, and <em>gulp styles </em>tasks above &#8211; other useful tasks include</p>
<ul>
<li>gulp clean
<ul>
<li><span>Removes </span><code>/pub/static</code><span> directory content.</span></li>
</ul>
</li>
<li>gulp dev
<ul>
<li><span>Runs </span><a href="https://www.browsersync.io/">browserSync</a><span> and </span><code>inheritance</code><span>, </span><code>babel</code><span>, </span><code>styles</code><span>, </span><code>watch</code><span> tasks.</span></li>
</ul>
</li>
</ul>
<p>See the fronttools project page for a full list of gulp tasks or use the gulp default task.</p>
<h1>How to install a theme blank SASS child theme</h1>
<p>Usual Magento best practice dictates that instead of editing the parent them we extend it with a child theme. You extend <code>Snowdog/blank</code> the same way as <a href="http://devdocs.magento.com/guides/v2.0/frontend-dev-guide/themes/theme-inherit.html">any other theme</a>.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;theme xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:noNamespaceSchemaLocation=&quot;urn:magento:framework:Config/etc/theme.xsd&quot;&gt;
    &lt;title&gt;Gaiterjones/blank&lt;/title&gt;
    &lt;parent&gt;Snowdog/blank&lt;/parent&gt;
    &lt;media&gt;
        &lt;preview_image&gt;media/preview.jpg&lt;/preview_image&gt;
    &lt;/media&gt;
&lt;/theme&gt;
</pre>
<p>I tested this with my Docker environment and used the following script to extend theme blank SASS with my <code>Gaiterjones/blank</code> child theme.</p>
<p><code>curl -o- http://gaiterjones.com/dropbox/magento2/theme-blank-sass/child/install-child-theme-blank-sass.sh | bash</code></p>
<span class="collapseomatic collapse" id="id6812227348940"  tabindex="0" title="script to install theme-blank-sass child theme"    >script to install theme-blank-sass child theme</span><div id="target-id6812227348940" class="collapseomatic_content ">
[bash]
#!/bin/bash<br />
# GAITERJONES<br />
# blog.gaiterjones.com<br />
# script to install example theme-blank-sass child theme<br />
#<br />
set -e<br />
# variables<br />
RED=&#8217;&#92;&#48;33[0;31m&#8217;<br />
NC=&#8217;&#92;&#48;33[0m&#8217;</p>
<p># CHANGE THIS<br />
MAGENTO_DIR=&#8217;/var/www/dev/magento2&#8242;<br />
NVM_HOME=&#8217;/var/www&#8217;</p>
<p># start<br />
printf &quot;${RED}Installing theme-blank-sass child theme into Magento Root: ${MAGENTO_DIR}&#8230;\n\n${NC}&quot;<br />
n98-magerun2.phar maintenance:enable<br />
cd ${MAGENTO_DIR}/app/design/frontend<br />
curl https://pe.terjon.es/dropbox/magento2/theme-blank-sass/child/gaiterjones-blank-child-theme-blank-sass.tar | tar x<br />
${MAGENTO_DIR}/bin/magento setup:upgrade<br />
cd ${MAGENTO_DIR}/vendor/snowdog/frontools</p>
<p>printf &quot;${RED}Configuring Gaiterjones/blank theme.\n${NC}&quot;<br />
THEME_ID=&quot;$(n98-magerun2.phar dev:theme:list &#8211;format=csv \<br />
  | grep &#8216;Gaiterjones/blank&#8217; | cut -d, -f1)&quot; \<br />
  ; test -n &quot;${THEME_ID}&quot; \<br />
  &amp;&amp; n98-magerun2.phar config:set design/theme/theme_id &quot;${THEME_ID}&quot;</p>
<p>printf &quot;${RED}Installing new themes.json config&#8230;\n${NC}&quot;<br />
curl -o &quot;${MAGENTO_DIR}/dev/tools/frontools/config/themes.json&quot; https://gaiterjones.com/dropbox/magento2/theme-blank-sass/child/themes-blank-sass-parent-child.json<br />
printf &quot;${RED}Generating theme-blank-sass styles&#8230;\n${NC}&quot;<br />
export NVM_DIR=${NVM_HOME}/.nvm<br />
 [ -s &quot;$NVM_DIR/nvm.sh&quot; ] &amp;&amp; \. &quot;$NVM_DIR/nvm.sh&quot;<br />
gulp styles<br />
${MAGENTO_DIR}/bin/magento cache:clean<br />
n98-magerun2.phar maintenance:disable<br />
# done<br />
printf &quot;${RED}Installation complete.\n\n${NC}&quot;</p>
[/bash]
</div>
<p>The script extracts the <code>Gaiterjones/blank</code> child theme source files to <em>app/design/frontend/Gaiterjones/blank </em>and updates Magento. We need to also update the fronttools <em>themes.json </em>config file to let fronttools know where our child theme lives</p>
<pre class="brush: plain; title: ; notranslate">
{
  &quot;blank&quot;: {
    &quot;src&quot;: &quot;vendor/snowdog/theme-blank-sass&quot;,
    &quot;dest&quot;: &quot;pub/static/frontend/Snowdog/blank&quot;,
    &quot;locale&quot;: &#x5B;&quot;en_GB&quot;],
    &quot;postcss&quot;: &#x5B;&quot;plugins.autoprefixer()&quot;],
    &quot;ignore&quot;: &#x5B;&quot;.test&quot;]
  },
  &quot;gaiterjones-blank&quot;: {
    &quot;src&quot;: &quot;app/design/frontend/Gaiterjones/blank&quot;,
    &quot;dest&quot;: &quot;pub/static/frontend/Gaiterjones/blank&quot;,
    &quot;locale&quot;: &#x5B;&quot;en_GB&quot;],
    &quot;localeOverwrites&quot;: true,
    &quot;parent&quot;: &quot;blank&quot;,
    &quot;postcss&quot;: &#x5B;&quot;plugins.autoprefixer()&quot;]
  }  
}

</pre>
<p>Next I am activating the theme with n98-magerun2 and then I simply need to refresh the caches and run <em>gulp styles </em> again to create the CSS for our child theme.</p>
<pre class="brush: bash; title: ; notranslate">
gulp styles
${MAGENTO_DIR}/bin/magento cache:clean
</pre>
<p>Fronttools compiles and installs the CSS for our child theme which is now installed and ready to view.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-install-magento-sass-blank-child.gif" alt="magento 2 theme blank sass child theme install video" class="aligncenter" /></p>
<p>You can see theme blank SASS in action on my <a href="http://magento2.gaiterjones.com" target="_blank">development site</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/magento2-theme-blank-sass-parent-and-child-setup-and-installation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Docker Magento CE v2.4.x Development Deployment with PHP7.4, Apache2.4, REDIS, VARNISH, RabbitMQ, Scaleable</title>
		<link>https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/</link>
					<comments>https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 25 Jun 2017 13:31:05 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[magento2]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1694</guid>

					<description><![CDATA[Installing Magento 2 in a development environment can be time consuming. This is my Magento 2 development deployment for Docker which can be used to quickly create a new Magento...<a class="more-link" href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>Installing Magento 2 in a development environment can be time consuming. This is my Magento 2 development deployment for Docker which can be used to quickly create a new Magento 2 Open Source (formerly known as CE) environment, or switch between persistent development environment volumes.</p>
<h2>Features</h2>
<ul>
<li>PHP 7.4 and Apache 2.4 built on the latest PHUSION docker images</li>
<li>2 Redis servers for Session and System (including FPC)</li>
<li>MYSQL 8</li>
<li>PhpMyAdmin</li>
<li>Varnish 6 for FPC</li>
<li>RabbitMQ</li>
<li>Management container and Scale Manager for <a href="https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/">scaled service dynamic load balancing</a></li>
<li>composer, n98-magerun2, PHP Redis Admin, XDEBUG</li>
<li><b>Magento 2.4.2 (Feb 2021)</b></li>
</ul>
<h2>Requirements</h2>
<ul>
<li>Host server with min 2GB RAM</li>
<li>Docker Engine</li>
<li>Docker Compose 3.1</li>
</ul>
<h2>Base Images / Source for 2.4 deployment</h2>
<ul>
<li><a href="https://hub.docker.com/r/gaiterjones/magento2/">gaiterjones/magento2</a> for 2.4
<ul>
<li><a href="https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/magento240-build">https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/magento240-build</a></li>
<li>PHUSION
<ul>
<li><a href="https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/phusion1100-apache2-php7-4-build">https://github.com/gaiterjones/docker-magento2/tree/master/magento2/ubuntu/phusion1001-apache2-php7-4-build</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Deployment</h2>
<p>Here are the steps to deploy this Magento 2.4 development environment:</p>
<ul>
<li>Clone the source file repository from, GitHub
<ul>
<li>2.4
<ul>
<li>git clone https://github.com/gaiterjones/docker-magento2</li>
</ul>
</li>
</ul>
</li>
<li>Change into the Magento 2 directory
<ul>
<li>cd magento2</li>
</ul>
</li>
<li>Edit the .env file and set the working environment for your deployment :
<ul>
<li>APPDOMAIN=dev.com
<ul>
<li>the domain name for the magento installation</li>
</ul>
</li>
<li>SMTP=XXX
<ul>
<li>the smtp gateway for your deployment, required for Magento email.</li>
</ul>
</li>
<li>MAGENTO_URL=http://magento2.dev.com
<ul>
<li>the Magento URL for your deployment</li>
</ul>
</li>
<li>MAGENTO_REPO_USERNAME/PASSWORD
<ul>
<li>your Magento repo authentication details required for Magento installation</li>
</ul>
</li>
<li>CONTAINERDATA=/home/docker/data/
<ul>
<li>Used for persistent container data</li>
</ul>
</li>
</ul>
</li>
<li>Edit docker-compose.yml
<ul>
<li>You can remove the Manager and Memcache service here if you do not want to deploy the scale manager.</li>
<li>for mysql persistent data uncomment the following from the mysql image
<ul>
<li><strong>#</strong>&#8211; &#8220;${CONTAINERDATA}/${PROJECT_NAME}/mysql/dev1:/var/lib/mysql&#8221;</li>
</ul>
</li>
<li>If you are using Nginx as a container reverse proxy change the ports and networks for the varnish service accordingly.</li>
</ul>
</li>
<li>Generate a Varnish Secret
<ul>
<li>You can create a new <a href="https://varnish-cache.org/docs/trunk/users-guide/run_security.html"><em>varnish secret</em></a> by running <em>newsecret.sh</em> in the varnish folder.</li>
</ul>
</li>
<li>BUILD
<ul>
<li><span>docker-compose build</span></li>
</ul>
</li>
<li>START
<ul>
<li><span>docker-compose up -d</span>
<ul>
<li>Allow 60 seconds after starting for composer to initialise</li>
</ul>
</li>
</ul>
</li>
<li>Install Magento Sample Data (optional)
<ul>
<li><span>docker exec -it magento2_php-apache_1 install-sampledata</span>
<ul>
<li><span>ignore error </span><em>Can&#8217;t run this operation: deployment configuration is absent.</em></li>
</ul>
</li>
</ul>
</li>
<li>Install Magento
<ul>
<li><span>docker exec -it magento2_php-apache_1 install-magento</span></li>
</ul>
</li>
</ul>
<h2>Script install</h2>
<p>For a quick test, spin up a Type 2 <a href="https://www.packet.net/">packet.net</a> server running Ubuntu LTS 20.04, install Docker CE and docker compose and then run</p>
<p><code>docker exec -it --user magento magento2_php-apache_1 su root -c "curl -o- https://gaiterjones.com/dropbox/magento2/docker/install.sh | bash"</code></p>
<p>&nbsp;</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-install-magento240.gif" alt="magento 2 docker containers install video" class="aligncenter" /></p>
<h2>Testing</h2>
<ul>
<li>frontend
<ul>
<li style="list-style-type: none;">
<ul>
<li><em><strong>http://magento2.dev.com</strong></em></li>
</ul>
</li>
</ul>
<ul>
<li style="list-style: none;"><img loading="lazy" decoding="async" style="padding: 1px; border: 1px solid #021a40;" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/Image.png" alt="" width="500" height="311" class="aligncenter wp-image-1695" /></li>
</ul>
</li>
<li>backend
<ul>
<li style="list-style-type: none;">
<ul>
<li><em><strong>http://magento2.dev.com/admin/</strong></em>
<ul>
<li>login using the credentials you set in .env</li>
</ul>
</li>
<li>Configure Varnish FPC
<ul>
<li><span>Stores-&gt; Configuration -&gt; Advanced -&gt; Full Page Cache</span></li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li style="list-style: none;"><img loading="lazy" decoding="async" style="padding: 1px; border: 1px solid #021a40;" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/Image-1.png" alt="" width="500" height="401" class="aligncenter wp-image-1696" /></li>
<li>Test from containers with curl (optional)
<ul>
<li><em>curl -I -H &#8220;host: magento2.dev.com&#8221; magento2_php-apache_1:80</em></li>
<li><em>curl -H &#8220;host: magento2.dev.com&#8221; magento2_php-apache_1:80/healthcheck.php</em></li>
</ul>
</li>
<li>n98-magerun2
<ul>
<li><span>docker exec -it &#8211;user magento magento2_php-apache_1 /usr/local/bin/n98-magerun2.phar</span></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Persistent volumes</h2>
<p>Your development deployment data will be lost when you restart the php-apache or sql containers. If you want data to persist after installation perform the following steps:</p>
<ul>
<li>Tar the Magento source files in the php-apache container
<ul>
<li>docker exec -it &#8211;user magento magento2_php-apache_1 tar -cvf /home/data/magento2.tar /var/www/dev</li>
<li>The tar file will be saved to the docker container data folder specified in .env</li>
</ul>
</li>
<li>Stop the containers
<ul>
<li>docker-compose down -v</li>
</ul>
</li>
<li>Untar to host
<ul>
<li>tar -xvf magento2.tar</li>
</ul>
</li>
<li>Move the /var/www/dev folder to your persistent data folder i.e. /home/docker/data/magento2/dev1</li>
<li>Uncomment the data volume in docker-compose.yml
<ul>
<li>#- &#8220;${CONTAINERDATA}/${PROJECT_NAME}/dev1:/var/www/dev&#8221;</li>
</ul>
</li>
<li>Restart containers, Magento data is now persistent.</li>
</ul>
<h2>Scaling php-apache</h2>
<p>You can scale the php-apache Magento service with</p>
<p><em>docker-compose scale php-apache=X</em></p>
<p>See <a href="https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/">this post for more information</a>.</p>
<h2>manager container</h2>
<p>In production I prefer to use a management container for all Magento admin and cli commands. The manager container can be used as the main administration container for your production environment. You should move all cron jobs to the manager and you can also move web administration to the manager container. This will free up the php-apache container just to be used to serve frontend web requests and allows you to use the scale function. You will also notice that separating cron tasks into a separate container reduces the memory requirement of the php-apache container significantly.</p>
<p>To start an admin bash session in the management container use<br />
<span></span></p>
<div><code>docker exec -i-t --user magento magento2_php-apache_1 /bin/bash</code></div>
<h2>References</h2>
<ul>
<li><a href="https://github.com/fballiano"><span>Fabrizio Balliano</span></a></li>
<li><a href="https://github.com/alexcheng1982">Alex Cheng</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/feed/</wfw:commentRss>
			<slash:comments>18</slash:comments>
		
		
			</item>
		<item>
		<title>Docker Mono Host Magento 2 Service Scaling and Dynamic Load Balancing with VARNISH</title>
		<link>https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/</link>
					<comments>https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 18 Jun 2017 16:30:30 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Magento2]]></category>
		<category><![CDATA[Scaled Services]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[magento2]]></category>
		<category><![CDATA[scale]]></category>
		<category><![CDATA[varnish]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1674</guid>

					<description><![CDATA[As I started building Docker service container images for Magento 2 CE development I got interested in the concept of dynamic service load balancing on a single host. Having already...<a class="more-link" href="https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>As I started building <a href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/">Docker service container images for Magento 2</a> CE development I got interested in the concept of dynamic service load balancing on a single host. Having already created a <a href="https://blog.gaiterjones.com/docker-mono-host-service-scaling-and-dynamic-load-balancing-with-nginx/">dynamic load balancer using NGINX</a> I wanted to do the same for Magento 2 using <strong>Varnish</strong>.</p>
<p>My Magento 2 service container images include REDIS services for the Magento session and system cache and a Varnish service for the full page cache. Varnish is an HTTP accelerator designed for content-heavy dynamic web sites and is the recommended full page cache system for Magento 2.</p>
<figure id="attachment_1690" aria-describedby="caption-attachment-1690" style="width: 1280px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/magento2-docker-network.png" alt="" width="1280" height="1024" class="size-full wp-image-1690" /><figcaption id="caption-attachment-1690" class="wp-caption-text">Magento 2 Docker Network</figcaption></figure>
<p>Varnish is configured via the Varnish Configuration Language (VCL) config file. By configuring multiple backend servers in VCL and grouping them into a director we can create a Varnish <a href="https://varnish-cache.org/docs/trunk/users-guide/vcl-backends.html">load balancer</a>.</p>
<span class="collapseomatic collapse" id="id681222734d019"  tabindex="0" title="Varnish Magento 2 load balancing VCL"    >Varnish Magento 2 load balancing VCL</span><div id="target-id681222734d019" class="collapseomatic_content ">
<pre>[text]
backend magento2_php_apache_1 {
.host = &quot;x.x.x.2&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_2 {
.host = &quot;x.x.x.8&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_3 {
.host = &quot;x.x.x.10&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_4 {
.host = &quot;x.x.x.11&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
backend magento2_php_apache_5 {
.host = &quot;x.x.x.9&quot;;
.port = &quot;80&quot;;
.probe = {.request =
&quot;GET /healthcheck.php HTTP/1.1&quot; &quot;Host: magento2.gaiterjones.com&quot; &quot;Connection: close&quot; &quot;Accept: text/html&quot;;.timeout = 1s;.interval = 30s;.window = 10;.threshold = 8;}
}
sub vcl_init {
new cluster1 = directors.round_robin();
cluster1.add_backend(magento2_php_apache_1);
cluster1.add_backend(magento2_php_apache_2);
cluster1.add_backend(magento2_php_apache_3);
cluster1.add_backend(magento2_php_apache_4);
cluster1.add_backend(magento2_php_apache_5);
}
[/text]</pre>
</div>
<h2>Scale Manager</h2>
<p>I use a service container called <em>php-apache</em> to run the Magento core code. Docker compose allows you to scale containers on a single host, so for example with the command</p>
<p><em>docker-compose scale php-apache=5</em></p>
<p>I can quickly scale the Magento2 php-apache service up to 5 containers, that is 5 instances of the php-apache service running the Magento2 core php code and apache web server.</p>
<p>The scale manager service monitors docker processes and detects when the php-apache service is scaled up or down. When a change is detected it dynamically creates the VCL configuration required to tell Varnish about the changes and applies these to the Varnish server.</p>
<figure id="attachment_1676" aria-describedby="caption-attachment-1676" style="width: 500px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" style="padding: 1px; border: 1px solid #021a40;" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/magento2-scale-demo.jpg" alt="" width="500" height="487" class="size-full wp-image-1676" /><figcaption id="caption-attachment-1676" class="wp-caption-text">Magento 2 Scale Demo</figcaption></figure>
<h2>Magento 2 Scale Demo</h2>
<p>In the video below I start with one running instance of the Magento 2 service, I then scale the service up to 5 and using the scale demo page (which is not cached by Varnish) on my <a href="http://magento2.gaiterjones.com/">Magento 2 dev site</a> to analyse the scale manager output data and display the running Magento 2 service containers.</p>
<p>As I refresh the page the Magento 2 container rendering the page is highlighted in yellow. you can see how Varnish round robins between the 5 available containers. Finally I scale the service back down and manually update the Varnish server config via the command line php script on the manager.</p>
<p>Another way to see the round robin connection distribution from varnish is to load up a <em>phpinfo()</em> page, you will see the SERVER_ADDR variable changing with each container that processes the request.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-magento2-scaledemox2.gif" alt="docker scale service dynamic load balancing with nginx demo video" class="aligncenter" /></p>
<p>Would you actually run 5 Magento 2 php-apache services? Good question! For true resilience and load balancing you would need multiple hosts and a Docker swarm. Multiple service containers on a single host do at least provide a simple level of redundancy and host server load balancing, I would definitely consider using it in production especially with a multi core server.</p>
<p>Many thanks to <a href="https://github.com/fballiano/docker-magento2">Fabrizio Balliano</a> for the inspiration and assistance.</p>
<p>See <a href="https://blog.gaiterjones.com/docker-magento-2-development-deployment-php7-apache2-4-redis-varnish-scaleable/">this post</a> for instructions on how to deploy this Magento 2 development environment.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/docker-mono-host-magento-2-service-scaling-and-dynamic-load-balancing-with-varnish/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Docker Mono Host Service Scaling and Dynamic Load Balancing with NGINX</title>
		<link>https://blog.gaiterjones.com/docker-mono-host-service-scaling-and-dynamic-load-balancing-with-nginx/</link>
					<comments>https://blog.gaiterjones.com/docker-mono-host-service-scaling-and-dynamic-load-balancing-with-nginx/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 11 Jun 2017 11:39:16 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[NGINX]]></category>
		<category><![CDATA[Scaled Services]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[dynamic load balancing]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[scaled services]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1663</guid>

					<description><![CDATA[Whilst building containers for Magento 2 I came across the docker compose scale command which allows you to easily duplicate and scale containers running a service in Docker. For example...<a class="more-link" href="https://blog.gaiterjones.com/docker-mono-host-service-scaling-and-dynamic-load-balancing-with-nginx/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>Whilst building containers for Magento 2 I came across the docker compose <a href="https://docs.docker.com/compose/reference/scale/">scale command</a> which allows you to easily duplicate and scale containers running a service in Docker.</p>
<p>For example if I have a web application service called php-apache</p>
<p><em>docker-compose scale php-apache=10</em></p>
<p>Will start another 9 containers running the php-apache service giving me 10 containers running the same php-apache web application service.</p>
<p>Of course if you want to have real resilience and load sharing <a href="https://docs.docker.com/engine/swarm/">Docker swarm</a> is the solution so the question is, <strong>are there any benefits from scaling a service in mulitple containers on a single host</strong>?</p>
<p>Well, yes, because you can still load balance the traffic to your application and achieve a basic level of container resilience.</p>
<p>Scaled services will only work for applications that use private ports as multiple Docker containers cannot share the same public port. I use an NGINX service container as a reverse proxy to my web application services with NGINX listening on the host public http port, proxying traffic to the service containers on their private internal container http ports.</p>
<p>This scenario can scale easily and there are some <a href="http://southworks.com/blog/2015/07/17/docker-compose-scaling-multi-container-applications/">documented examples</a> that describe how to load balance Docker scaled web application services, however all the examples I found require manual configuration and a restart of the load balancer to update it when service containers are scaled up or down.</p>
<p>I wanted to create a <em>dynamic</em> scaled service where the load balancer or proxy is dynamically updated when services are scaled up or down.</p>
<p>NGINX as a reverse proxy <a href="http://nginx.org/en/docs/http/load_balancing.html">will also load balance</a> when multiple upstream hosts are configured for a website but the default configuration file must be manually edited, saved and NGINX restarted before the changes take affect.</p>
<p>A bit of <em>googling</em> around uncovered a <a href="https://github.com/yzprofile/ngx_http_dyups_module">module</a> that allows you to dynamically update the NGINX upstream host configuration. I compiled the module into my existing NGINX service container and tested it and was able to dynamically add and remove upstream hosts, perfect for dynamically scaling Docker services!</p>
<p><img loading="lazy" decoding="async" style="padding: 1px; border: 1px solid #021a40;" src="https://blog.gaiterjones.com/wp-content/uploads/2017/06/docker-scaledemo-app-1.jpg" alt="" width="500" height="535" class="aligncenter wp-image-1670 size-full" /></p>
<h1>Scaledemo Application</h1>
<p>To demonstrate how Docker Mono Host Service Scaling and Dynamic Load Balancing with NGINX works I put together a group of containers to simulate a scaled web application :</p>
<ul>
<li>manager
<ul>
<li>A php service container that acts as the manager for the scaled services project.</li>
</ul>
</li>
<li>nginx
<ul>
<li>An NGINX container compiled with the <em>ngx_http_dyups</em> dynamic upstream module.</li>
</ul>
</li>
<li>php-apache
<ul>
<li>A php7, Apache2 service container that will run my demo &#8216;Bean Counter&#8217; web application.</li>
</ul>
</li>
<li>memcached
<ul>
<li>Cache server used by the manager to store Docker data, and by the web application to store the &#8216;Bean Counter&#8217; data.</li>
</ul>
</li>
</ul>
<h1>Manager</h1>
<p>Dynamic updates to NGINX are carried out by the manager service container. It pulls Docker system information from the Docker host via a cron job every 60 seconds, parses the data for running service containers that match the configured project web application service container (php-apache) and generates an NGINX upstream host configuration.</p>
<p>The manager compares the upstream host configuration running on NGINX with the generated configuration from Docker. If they differ it updates NGINX via php-curl with the new configuration. The parsed manager Docker data is stored on the memcache server so that it is available to other services.</p>
<p>When I scale the php-apache service up or down NGINX is dynamically configured with the changes at the next manager update, or heartbeat. I can also manually force the update via a cli command on the manager.</p>
<h1>Demo</h1>
<p>Watch the video below to see the scale demo in action.</p>
<p>In the video I start the containers with docker compose, scale php-apache up to 10 instances and check the dynamic update and round robin load balancing via the demo web application that parses the manager data from memcache and also increments a counter.</p>
<p>I then scale it up again to 20 instances and manually update the nginx configuration via the manager. You can see NGINX load balancing the web application with round robin requests to each of the 20 service containers as I click the refresh button to increment the bean counter and reload the page. The container that served the page is highlighted in yellow.</p>
<p>Finally I scale the service back down to 2 instances and stop the containers.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-scaledemox2.gif" alt="docker scale service dynamic load balancing with nginx demo video" class="aligncenter" /><br />
You can build the Docker containers and try out the demo yourself using the docker-compose files from <a href="https://github.com/gaiterjones/docker-scaledemo">GitHub</a>.</p>
<ul>
<li>Clone the project files
<ul>
<li>git clone https://github.com/gaiterjones/docker-scaledemo</li>
</ul>
</li>
<li>Build the containers
<ul>
<li>cd scaledemo</li>
<li>docker-compose build</li>
</ul>
</li>
<li>Make sure there are no other service using port 80 on your host and start the containers
<ul>
<li>docker-compose up -d</li>
</ul>
</li>
<li>Point your browser at http://scaledemo.dev.com (which should resolve to your Docker host) to see the demo page</li>
<li>Scale the php-apache container
<ul>
<li>docker-compose scale php-apache=5</li>
</ul>
</li>
</ul>
<p>To manually update NGINX from the scale manager</p>
<ul>
<li>Connect to the manager container
<ul>
<li> docker exec -t -i scaledemo_manager_1 /bin/bash
<ul>
<li>or <em>docker exec magento2_manager_1 php cron.php scalemanager</em></li>
</ul>
</li>
</ul>
</li>
<li>run the scalemanager php script
<ul>
<li>php cron.php update scalemanager</li>
</ul>
</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/docker-mono-host-service-scaling-and-dynamic-load-balancing-with-nginx/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to run FHEM as a Docker Container on a Raspberry Pi</title>
		<link>https://blog.gaiterjones.com/how-to-run-fhem-as-a-docker-container-on-a-raspberry-pi/</link>
					<comments>https://blog.gaiterjones.com/how-to-run-fhem-as-a-docker-container-on-a-raspberry-pi/#comments</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Wed, 31 May 2017 17:58:27 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Home Automation]]></category>
		<category><![CDATA[Raspberry Pi]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[fhem]]></category>
		<category><![CDATA[home automation]]></category>
		<category><![CDATA[raspberry pi]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1640</guid>

					<description><![CDATA[I use FHEM as the engine for home automation tasks on my Raspberry Pi. This is how to build and run FHEM as a container in Docker on your Raspberry...<a class="more-link" href="https://blog.gaiterjones.com/how-to-run-fhem-as-a-docker-container-on-a-raspberry-pi/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>I use <a href="http://fhem.de">FHEM</a> as the engine for home automation tasks on my Raspberry Pi. This is how to build and run FHEM as a container in Docker on your Raspberry Pi Zero, Pi2 or Pi3.</p>
<p><img decoding="async" src="https://blog.gaiterjones.com/dropbox/docker-fhem-container-installation.gif" alt="fhem docker container installation" class="aligncenter" /></p>
<h1>Install Docker</h1>
<p>Installing Docker is a no brainer</p>
<pre class="brush: plain; title: ; notranslate">
curl -sSL get.docker.com | sh
sudo usermod your-username -aG docker
reboot
</pre>
<h1>Install docker-compose</h1>
<p>Docker-compose makes building, starting and stopping Docker containers really simple.</p>
<pre class="brush: plain; title: ; notranslate">
apt-get -y install python-pip
pip install docker-compose
</pre>
<h1>Build the container</h1>
<p>Pull the container build files from github and run docker-compose build to build the container image.</p>
<pre class="brush: plain; title: ; notranslate">
git clone https://github.com/gaiterjones/docker-rpi-fhem
cd docker-rpi-fhem
docker-compose build
</pre>
<h1>Start the container</h1>
<pre class="brush: plain; title: ; notranslate">
docker-compose up -d
</pre>
<h1>Connect to FHEM</h1>
<p>Enter the following url into your browser to connect to FHEM.</p>
<p><strong>http://my.pi:8803/fhem</strong></p>
<p>Update FHEM by entering with the <em>update </em>command.<br />
Restart FHEM by entering the <em>shutdown restart</em> command.</p>
<p>FHEM is now running and up to date.</p>
<p>You can start configuring it or copy your existing FHEM config or editing the <em>fhem.cfg</em> file in <em>./fhem</em>. This is a Docker volume on the host mapped to <em>/opt/fhem</em> in the container. Docker host volumes will persist when you bring down the container (docker-compose down) or clear the volume caches (docker-compose down -v) so you will not lose your configuration or logs when the container restarts or is rebuilt.</p>
<h1>Customising</h1>
<p>Take a look at docker-compose.yml</p>
<pre class="brush: plain; title: ; notranslate">
# RPI
# FHEM CONTAINER
#
version: &quot;3&quot;

services:
    server:
        build: ./build/
        hostname: fhem
        domainname: home.com
        privileged: true
        ports:
          - &quot;8083:8083&quot;
          - &quot;7072:7072&quot;
        expose:
            - 8083
            - 7072
        volumes:
            - ./fhem:/opt/fhem
            #- /dev/ttyUSB0:/dev/ttyUSB0
        networks:
            - server
        restart: always
        healthcheck:
           test: &#x5B;&quot;CMD-SHELL&quot;, &quot;echo 'QUIT' | nc -w 5 localhost 7072 &gt; /dev/null 2&gt;&amp;1 &amp;&amp; echo 'FHEM OK'&quot;]
           interval: 15m
           timeout: 10s
           retries: 3
networks:
    server:
</pre>
<p>You can see we are configuring global ports 8083 and 7072 on the host as well as exposing them on the container. I have an SSL certificate installed on my Pi and use Nginx as a frontend proxy to my Docker containers, this lets me connect to FHEM using SSL</p>
<p><strong>https://my.pi/fhem</strong></p>
<p>To remove the global host ports delete or comment out the ports config leaving just the expose config. Nginx can be configured to proxy to fhem using the following configuration:</p>
<pre class="brush: plain; title: ; notranslate">
# FHEM
location /fhem {
  proxy_pass http://fhem_container_1:8083/fhem;
}
</pre>
<p>The container runs in privileged mode which gives it access to the hosts hardware and devices. If you are using external USB devices connected to the Pi you must add them as a volume in the container i.e.</p>
<p><strong>&#8211; /dev/ttyUSB0:/dev/ttyUSB0</strong></p>
<p>Make sure the fhem user running in the container has the same user id as your host user, in this case uid 1001.</p>
<pre class="brush: plain; title: ; notranslate">	 	 
user@raspberrypi:/dev# id your-user-name	 	 
uid=1001(your-user-name) gid=1001(your-user-name) groups=1001(your-user-name),27(sudo),996(docker)	 	 
</pre>
<p>This will ensure there are no permission problems when the container tries to access devices on the host.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/how-to-run-fhem-as-a-docker-container-on-a-raspberry-pi/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Migrating PHP Web Applications to Docker Containers</title>
		<link>https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/</link>
					<comments>https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/#respond</comments>
		
		<dc:creator><![CDATA[PAJ]]></dc:creator>
		<pubDate>Sun, 07 May 2017 17:50:28 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[containerisation]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[upgrade]]></category>
		<guid isPermaLink="false">http://blog.gaiterjones.com/?p=1549</guid>

					<description><![CDATA[I have been working with PHP for about 6 years now and my first public facing development server is about the same age. It started life as a 32 bit...<a class="more-link" href="https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/" title="Continue reading">Continue reading</a>]]></description>
										<content:encoded><![CDATA[<p>I have been working with PHP for about 6 years now and my first public facing development server is about the same age. It started life as a 32 bit 1GB Linode probably running Ubuntu v10.x, it survived a couple of OS upgrades and even a pseudo kernel shift to 64bit and ended life as a Linode 4096 running Ubuntu 14.x.</p>
<p>Maintaining servers whether they are physical or virtual is a real pain in the neck, as time goes by you develop apps, you install more and more software and your simple php development platform starts to become quite complex. When it comes to a major OS update e.g. Ubuntu 14LTS to 16LTS where mysql and php versions are changing then keeping all your (now live) websites, blogs and apps running can become a real challenge.</p>
<p>In an ideal world you would have multiple servers designed specifically for the apps they are running, in the real world when we are talking about personal websites, blogs and forums everything ends up running on the same server. The longer you postpone an operating system upgrade the harder it gets to upgrade, and whilst some people live by the &#8216;if it&#8217;s running don&#8217;t break it&#8217; theory when developing apps you want to make sure you are staying up to date with best practice and are aware what is being deprecated or no longer supported. Again the longer you ignore updates to PHP the harder it will be to update your PHP apps!</p>
<p>It&#8217;s a bit of a catch 22 situation, you need new server hardware, or an operating system but you can&#8217;t just upgrade in one go because too many apps will be affected resulting in a lot of downtime whilst you fix all the broken code and you can&#8217;t migrate to a new server because you know some of your apps won&#8217;t run.</p>
<p>As soon as you build a new server the process starts again and the next upgrade becomes just as challenging.</p>
<p>What is the solution? &#8211; containerisation.</p>
<h1>containerisation with docker</h1>
<p>Docker containers wrap up a piece of software in a complete filesystem that contains everything it needs to run: code, runtime, system tools, system libraries – anything you can install on a server. This guarantees that it will always run the same, regardless of the environment it is running in.</p>
<p>By moving each of my apps and server services into a container customised for the requirements of that app, be it a specific PHP or MySQL version or operating system I containerised (virtualised) all my server applications: php, mail, cloud storage, vpn, webapps, blogs, forums, Magento etc. into new zero administration servers which I wil never have to worry about upgrading!</p>
<p>All the old apps you know are not compatibile with the latest version of PHP (i.e. Magento 1.x) can stay running in a container customised for their requirements. The docker host server can now run a very minimal operating system, ideally with just Docker installed making future upgrades pretty uncomplicated.</p>
<p>Because all your apps are in containers moving to a new server is as simple as moving the container configuration and data files to the new server and starting the containers, you no longer have to worry about upgrade compatibility issues as your application is running in an container image that in theory will never change!</p>
<figure id="attachment_1589" aria-describedby="caption-attachment-1589" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2017/04/docker-folders.png" alt="" width="600" height="480" class="size-full wp-image-1589" /><figcaption id="caption-attachment-1589" class="wp-caption-text">Docker Data Folders</figcaption></figure>
<p>The golden rule to follow is to ensure that you always treat your containers as volatile storage and never store live data in them, or commit configurations that are not included in your configuration files.</p>
<p>By separating your application data into persistent docker volumes located in logically named folders basic housekeeping tasks like log management and backups are now also simplified. With all app data located in data folders, your container (application) data can be easily backed up. Log files are also easy to manage because they are consolidated into Docker&#8217;s central logging engine, all your log data can easily be centrally stored and analysed.</p>
<figure id="attachment_1586" aria-describedby="caption-attachment-1586" style="width: 600px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" src="https://blog.gaiterjones.com/wp-content/uploads/2017/03/docker-network-1.png" alt="" width="600" height="480" class="size-full wp-image-1586" /><figcaption id="caption-attachment-1586" class="wp-caption-text">Docker Network Diagram</figcaption></figure>
<p>In practice Docker just works, the containers start and stop in seconds, and in some cases your apps will run much faster. There is a lot of work in configuring the container to replicate the environment you want, but once your Docker file is written it becomes a good template for future apps.</p>
<p>It&#8217;s easy to get carried away containerising everything so you have to monitor the host server resources you are using, I ended up with over 40 running containers which maxed out the RAM in a 4GB Linode resulting in containers crashing because they suddenly ran out of memory. I upgraded to an 8GB Linode where the ram usage now averages at just over 4GB for 40 running containers leaving me room for expansion.</p>
<p>I recommend building your containers using docker compose. <a href="https://docs.docker.com/compose/">Docker compose</a> lets you keep your container configuration in one folder and provides an easy command line interface to start, stop and build containers. Here for example is the docker composer file for my Exim4 mail server container.</p>
<span class="collapseomatic collapse" id="id681222734f930"  tabindex="0" title="Show Exim4 docker-compose.yml"    >Show Exim4 docker-compose.yml</span><div id="target-id681222734f930" class="collapseomatic_content ">
[text]
# MAIL RELAY<br />
# EXIM4 + SPAMASSASIN<br />
#<br />
# Mail relay with configurable relay virtual domains and smtp auth<br />
#<br />
#<br />
version: &#8216;3&#8217;</p>
<p>services:<br />
    exim4:<br />
      build: ./exim4/<br />
      hostname: host<br />
      domainname: mail.com<br />
      # mail server from these networks :<br />
      networks:<br />
        &#8211; server<br />
      ports:<br />
        &#8211; &quot;25:25&quot;<br />
      expose:<br />
        &#8211; 465<br />
        &#8211; 587<br />
      volumes:<br />
        &#8211; ./virtual:/etc/exim4/virtual<br />
      restart: always<br />
      healthcheck:<br />
       test: [&quot;CMD-SHELL&quot;, &quot;echo &#8216;QUIT&#8217; | nc -w 5 mail.server.co.uk 25 &gt; /dev/null 2&gt;&amp;1 &amp;&amp; echo &#8216;SMTP OK&#8217;&quot;]
       interval: 1h<br />
       timeout: 10s<br />
       retries: 3</p>
<p>    sa:<br />
      build: ./sa/<br />
      hostname: sa<br />
      domainname: server.co.uk<br />
      depends_on:<br />
       &#8211; exim4<br />
      networks:<br />
        &#8211; server<br />
      expose:<br />
        &#8211; 783<br />
      restart: always</p>
<p># define networks<br />
networks:<br />
  server:<br />
[/text]
</div>
<p>Here you see the docker compose file creates two services, Exim4 and Spam Assassin. The file also configures health checks and networking. More about building containers such as this Exim4 mail server with spam assassin will follow in another post.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.gaiterjones.com/migrating-php-web-applications-to-docker-containers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
