<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ohffs</title>
    <description>The latest articles on DEV Community by ohffs (@ohffs).</description>
    <link>https://dev.to/ohffs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F94939%2F3915ba4f-d79b-45cc-90ab-119fea6f0154.jpeg</url>
      <title>DEV Community: ohffs</title>
      <link>https://dev.to/ohffs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ohffs"/>
    <language>en</language>
    <item>
      <title>Traefik v2 with Docker Swarm</title>
      <dc:creator>ohffs</dc:creator>
      <pubDate>Fri, 06 Dec 2019 09:55:14 +0000</pubDate>
      <link>https://dev.to/ohffs/traefik-v2-with-docker-swarm-2cgh</link>
      <guid>https://dev.to/ohffs/traefik-v2-with-docker-swarm-2cgh</guid>
      <description>&lt;h1&gt;
  
  
  Traefik v2 with Docker Swarm
&lt;/h1&gt;

&lt;p&gt;I've been a happy user of &lt;a href="https://docs.traefik.io/"&gt;Traefik&lt;/a&gt; all through the v1.x series but with v2.1 coming out I began to have a proper look at upgrading.  The docs are very thorough, but as with a lot of thorough docs also not very enlightening about 'how do I do the thing?'.&lt;/p&gt;

&lt;p&gt;So after a bit of faffing about, watching &lt;a href="https://www.youtube.com/watch?v=Gk9WER6DunE"&gt;yotube videos&lt;/a&gt; (the files here are modified versions of the compose-style ones attached to the video) etc I've got something running.  This is a very basic 'just get it up and running' example - mostly as an aide-memoire for myself and hopefully to give some pointers to other people migrating from v1 to v2.  I'm assuming familiarity with Traefik v1 so I'm not documenting everything line by line.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack files
&lt;/h2&gt;

&lt;p&gt;Our setup is a traefik instance running listening on an overlay network called 'proxy'.  Any web apps that need to talk to the outside world also sit on that network and have the magic traefik labels set so they get picked up.  So the v2 traefik file I have so far is :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.3"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;traefik&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik:v2.0&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;traefik&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt; &lt;span class="c1"&gt;# traefik dashboard&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--api.insecure=true&lt;/span&gt; &lt;span class="c1"&gt;# set to 'false' on production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--api.dashboard=true&lt;/span&gt; &lt;span class="c1"&gt;# see https://docs.traefik.io/v2.0/operations/dashboard/#secure-mode for how to secure the dashboard&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--api.debug=true&lt;/span&gt; &lt;span class="c1"&gt;# enable additional endpoints for debugging and profiling&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--log.level=DEBUG&lt;/span&gt; &lt;span class="c1"&gt;# debug while we get it working, for more levels/info see https://docs.traefik.io/observability/logs/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.swarmMode=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.exposedbydefault=false&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--providers.docker.network=proxy&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--entrypoints.web.address=:80&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--entrypoints.web-secured.address=:443&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--certificatesresolvers.mytlschallenge.acme.httpChallenge.entrypoint=web&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--certificatesresolvers.mytlschallenge.acme.email=you@whatever.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;letsencrypt:/letsencrypt&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;proxy&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.api.rule=Host(`traefik.yourdomain.com`)"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.api.service=api@internal"&lt;/span&gt; &lt;span class="c1"&gt;# Let the dashboard access the traefik api&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;letsencrypt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And a basic example wordpress stack file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.3"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;wordpress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wordpress&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;wp&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;WORDPRESS_DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db&lt;/span&gt;
      &lt;span class="na"&gt;WORDPRESS_DB_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exampleuser&lt;/span&gt;
      &lt;span class="na"&gt;WORDPRESS_DB_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;examplepass&lt;/span&gt;
      &lt;span class="na"&gt;WORDPRESS_DB_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exampledb&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;wordpress:/var/www/html&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;proxy&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.enable=true"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.wordpress.rule=Host(`wordpress.yourdomain.com`)"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.wordpress.entrypoints=web"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.services.wordpress.loadbalancer.server.port=80"&lt;/span&gt; &lt;span class="c1"&gt;# it seems you always need to give traefik a port so it 'notices' the service&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.wordpress-secured.rule=Host(`wordpress.yourdomain.com`)"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.wordpress-secured.entrypoints=web-secured"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;traefik.http.routers.wordpress-secured.tls.certresolver=mytlschallenge"&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:5.7&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exampledb&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exampleuser&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;examplepass&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_RANDOM_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1'&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;db:/var/lib/mysql&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;backend&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;wordpress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Using it
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# assuming you are on a swarm master node
docker network create --driver=overlay proxy
docker stack deploy -c traefik.yml traefik
docker stack deploy -c wordpress.yml wordpress
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After a short delay you should be able to visit the urls defined in the stack files on both http and https.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI/CD
&lt;/h2&gt;

&lt;p&gt;As each traefik-enabled service now has labels that have names to make them unique (eg, &lt;code&gt;traefik.http.routers.wordpress.entrypoints=web&lt;/code&gt;) having a stack file with something like &lt;code&gt;traefik.http.routers.${STACK_NAME}.entrypoints=web&lt;/code&gt;, &lt;code&gt;traefik.http.routers.${STACK_NAME}-secured.entrypoints=web-secured&lt;/code&gt; is probably worth thinking about so you can do :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export STACK_NAME=wordpress
docker stack deploy -c wordpress.yml ${STACK_NAME}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and tie things together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further
&lt;/h2&gt;

&lt;p&gt;Obviously this is a &lt;em&gt;very&lt;/em&gt; basic setup.  To take this into production you'd be looking at consul for the letsencrypt store, sensible deploy: flags, not giving traefik access&lt;br&gt;
to the docker socket directly etc.  But as a 'how on earth do I use v2' I hope it helps someone and saves them having to dig through things for&lt;br&gt;
as long as I did.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>traefik</category>
      <category>swarm</category>
    </item>
    <item>
      <title>Local slang or words in code</title>
      <dc:creator>ohffs</dc:creator>
      <pubDate>Mon, 18 Mar 2019 18:27:48 +0000</pubDate>
      <link>https://dev.to/ohffs/local-slang-or-words-in-code-3j8f</link>
      <guid>https://dev.to/ohffs/local-slang-or-words-in-code-3j8f</guid>
      <description>&lt;p&gt;I was looking back on a bit of Python code I wrote a year or two ago for a nanotechnology facility and remembered that as part of their process they move the 'device' back and forth a few nanometers before finalising their settings.  I coded the function that did it as '&lt;a href="https://www.collinsdictionary.com/dictionary/english/shoogle"&gt;shoogle&lt;/a&gt;'.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(ˈʃʊɡəl ) or shoogie (ˈʃʊɡiː) dialect, mainly Scottish&lt;br&gt;
verb&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
to shake, sway, or rock back and forth
noun&lt;/li&gt;
&lt;li&gt;
a rocking motion; shake&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;I still feel absurdly pleased with myself that some £50m nanotech plant is 'shoogling' every few hours.&lt;/p&gt;

&lt;p&gt;I got to wondering - what words have you snuck into code that you are secretly pleased with?&lt;/p&gt;

</description>
      <category>development</category>
      <category>language</category>
      <category>patois</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Story of a little bug</title>
      <dc:creator>ohffs</dc:creator>
      <pubDate>Mon, 19 Nov 2018 11:02:46 +0000</pubDate>
      <link>https://dev.to/ohffs/story-of-a-little-bug-4ppb</link>
      <guid>https://dev.to/ohffs/story-of-a-little-bug-4ppb</guid>
      <description>&lt;p&gt;One of our applications has a feature where a user can toggle an option which sends an email out to notify someone else.  The email is delayed by 30 minutes so that the user can change their mind (or realise they toggled the wrong thing in the first place...).  All well and good.&lt;/p&gt;

&lt;p&gt;A while ago there was a small change to make to the code and email template, so we pushed out a new version.  That push is via &lt;a href="https://deployer.org/" rel="noopener noreferrer"&gt;deployer&lt;/a&gt; which does 'zero downtime' deploys by symlinking a release directory to a 'current' one which the app is actually served from.  It keeps the previous five releases by default so you can roll back if needed.  All well and good.&lt;/p&gt;

&lt;p&gt;The app uses a background queue to send out this particular email - the job is delayed by 30 minutes and before it finally sends it checks if the toggle is still in the 'yes - do that' mode.  When we deployed the mentioned change we manually restarted the whole queue just to make sure it was in sync with the new code.  Again, all was well and good - everything was working fine.  We pushed out another handful of small updates over the course of the day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six weeks later...
&lt;/h2&gt;

&lt;p&gt;We had an email from one of the office administrators saying they didn't think emails were going out from the system any more.  We'd had a fairly brutal power-cut just a week or so before and my first thought was 'oh, damn - something hasn't restarted properly'.  Although there hadn't been any errors caught by &lt;a href="https://sentry.io/welcome/" rel="noopener noreferrer"&gt;Sentry&lt;/a&gt; - our log monitor hadn't spotted anything either.&lt;/p&gt;

&lt;p&gt;Checking the queue status showed that it was marked as 'paused'.  I'd had that before where two apps were sharing a Redis instance and they got confused about which jobs they should be processing - sure enough there was another app on the server and it was pointing at the same Redis db.  So we switched the db value up one on the problematic app and restarted the queue - which were now showing as healthy and a test message went out ok.  "Phew!" I thought - nice easy fix and made a mental note to finally get round to making sure all the apps had a designated db so they never conflicted.  &lt;/p&gt;

&lt;p&gt;Then I started to think - 'hang on, that other app has Redis configured - but it doesn't actually use the queues.  It was just a default we've got into the habit of including as "we'll probably use Redis at some point, include the config by default" kinda deal.  So did a little more digging...&lt;/p&gt;

&lt;p&gt;Checking the apps own error log showed nothing of interest.  So checked the syslog on the server itself and saw lots of 'Could not open file /path/to/release/65/' messages from the queue worker before I had restarted them.  Which was... odd.  Especially as our log monitor hadn't picked it up.&lt;/p&gt;

&lt;p&gt;The queue workers are started via systemd and point to the &lt;code&gt;/path/to/current/&lt;/code&gt; so that they should be using the latest release when they are run.  But un-noticed by me, they &lt;em&gt;actually&lt;/em&gt; see the symlink and resolve it to the 'real' directory so had gone to '/path/to/release/65/' which was where 'current' was pointing at the time.&lt;/p&gt;

&lt;p&gt;Since the last manual 'restart the whole queue process' there had been five other small changes pushed out - each of those should have restarted the queue workers so it &lt;em&gt;shouldn't&lt;/em&gt; have been a problem.  But, again, un-noticed by me - the command used to restart the queues doesn't restart the master process - just tells the master process to restart the workers &lt;em&gt;based on it's own idea of the path&lt;/em&gt;.  So after the fifth push the master process was now pointing at a directory which the &lt;code&gt;deployer&lt;/code&gt; command had removed as being the sixth-oldest release...&lt;/p&gt;

&lt;p&gt;Sentry hadn't picked it up as it was never able to load enough of the code to register the handler.  It also turned out that when the server had been built the person hadn't run &lt;a href="https://puppet.com/" rel="noopener noreferrer"&gt;Puppet&lt;/a&gt; on it so it hadn't installed the log forwarding/monitor setup.  And the systemd process handler thought all was well as the master process continued to run quite happily as it had loaded all of it's code into RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up...
&lt;/h2&gt;

&lt;p&gt;So all in all - the system hadn't sent out a copy of the email for almost six weeks.  &lt;em&gt;Thankfully&lt;/em&gt; it was a very quiet time of year for that particular feature so only a handful of these notifications had gone awol.  But it was an interesting morning tracing back the errors, why all the layers of monitoring hadn't noticed, how the symlinking caught us out and piecing together the history of the server itself.&lt;/p&gt;

&lt;p&gt;And now in addition to the existing monitoring, I've taken a bit of the code from the front-end that showed us that the queues were 'paused' to begin with and used it to make a little cron job that &lt;em&gt;does&lt;/em&gt; alert Sentry if all isn't well.  &lt;em&gt;Probably&lt;/em&gt;... ;-)&lt;/p&gt;

</description>
      <category>devops</category>
      <category>email</category>
      <category>debugging</category>
      <category>php</category>
    </item>
    <item>
      <title>Basic HA setup with (docker|kubernetes)</title>
      <dc:creator>ohffs</dc:creator>
      <pubDate>Sat, 06 Oct 2018 14:30:01 +0000</pubDate>
      <link>https://dev.to/ohffs/basic-ha-setup-with-dockerkubernetes-3hjc</link>
      <guid>https://dev.to/ohffs/basic-ha-setup-with-dockerkubernetes-3hjc</guid>
      <description>

&lt;p&gt;We have a whole lot of web apps and services at work - most of them are not internet-facing as they are internal 'admin' type tools.  At the moment we run them as fairly 'dumb' KVM virtual machines (dumb in the sense that there's no automatic fail-over and no shared storage so each vm is a disk image on the server it's running on).&lt;/p&gt;

&lt;p&gt;I've been working on making the apps run inside of docker containers - initially just as a way of avoiding the annoying 'this needs PHP 5.3, that needs PHP 7.2, this needs python 2.7 + ...' issues.  But I started getting more into the idea of using Docker Swarm or Kubernetes to give a more 'seamless' deployment process and allow for some kind of automatic fail-over of the apps.&lt;/p&gt;

&lt;p&gt;After quite a lot of reading and experimentation - it feels like kubernetes is overkill for our needs.  We basically have 10-20 apps running - and the world doesn't end if they're offline for a short while.  The complexities of kubernetes seem quite high compared to Docker Swarm.  On the other hand - it doesn't feel like Swarm is winning out in the container world.&lt;/p&gt;

&lt;p&gt;Anyway - my current thinking is to go with the following setup :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3xServers running docker swarm (we have two nearby physical sites)&lt;/li&gt;
&lt;li&gt;A virtual IP managed by something like keepalived to be the primary 'in-road' to the cluster&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://traefik.io/"&gt;traefik&lt;/a&gt; to act as the swarm ingress&lt;/li&gt;
&lt;li&gt;Probably ceph as a storage layer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The end goal is that if a server running App-X goes down, then App-X is started on another server and traefik takes care of routing to the new instance.  If the primary server goes down, the keepalived brings up the IP address on another box and the traefik instance there starts handling the routing to the apps.&lt;/p&gt;

&lt;p&gt;Most of the tutorials &amp;amp; guides I've found are either 'running hello world in swarm!' or 'bringing up 10,000 pods inside GKE!' with very little in the 'I'd just like stuff to kinda work if the power cord is pulled out of a box by accident' kind of thing ;-)&lt;/p&gt;

&lt;p&gt;I'd be really interested in anyone's thoughts.  I'm hoping to try and document the process to fill in the 'bigger than hello-world, smaller than Walmart' gap I seem to be falling into ;-)&lt;/p&gt;


</description>
      <category>docker</category>
      <category>highavailablity</category>
      <category>kubernetes</category>
      <category>containers</category>
    </item>
  </channel>
</rss>
