<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Realm of Chaos - juju</title>
    <subtitle>Welcome to my notebook! I’m a Site Reliability Engineer who is curious, loves to learn and discover the nature of things.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://realmofchaos.xyz/tags/juju/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://realmofchaos.xyz"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2020-12-02T00:00:00+00:00</updated>
    <id>https://realmofchaos.xyz/tags/juju/atom.xml</id>
    <entry xml:lang="en">
        <title>WordPress Charm for k8s</title>
        <published>2020-12-02T00:00:00+00:00</published>
        <updated>2020-12-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thomas Cuthbert
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://realmofchaos.xyz/tech/wordpress-k8s-charm/"/>
        <id>https://realmofchaos.xyz/tech/wordpress-k8s-charm/</id>
        
        <content type="html" xml:base="https://realmofchaos.xyz/tech/wordpress-k8s-charm/">&lt;p&gt;Canonical uses the WordPress blogging system for all our company blogs. Earlier this year I was tasked with updating our WordPress charm from a Services Framework Juju Charm on OpenStack to a Kubernetes based Operator Framework Charm.&lt;&#x2F;p&gt;
&lt;p&gt;The WordPress Operator Charm is simple by design, the goal of the charm is to just provide the various configuration options for our WordPress Kubernetes image, which does all the heavy lifting. See the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git.launchpad.net&#x2F;charm-k8s-wordpress&#x2F;tree&#x2F;config.yaml&quot;&gt;config.yaml&lt;&#x2F;a&gt; file for details on what is supported, one option that can be useful during testing is &lt;code&gt;container_config&lt;&#x2F;code&gt;, which gives you the ability to pass through custom Kubernetes spec environment variables. For example, to enable debug level logging and ensuring you always have the latest image, you would set:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;microk8s.juju config wordpress container_config=&amp;#39;WORDPRESS_DEBUG: &amp;quot;1&amp;quot; imagePullPolicy: &amp;quot;always&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The image build process downloads the latest WordPress codebase and installs it behind an Apache web server, it then downloads the plugins all of our blogs depend on, such as, akismet anti-spam support, SSO with the openid teams plugin, and a variety of Canonical Open Source themes. By default the charm will use the current stable build here, however if you wish to customise the image you can fork the code and update the &lt;code&gt;image&lt;&#x2F;code&gt; charm config option to point to the location of your custom image.&lt;&#x2F;p&gt;
&lt;p&gt;To get started with the Operator Framework WordPress charm you will need a MySQL database running locally. As I write this post there is no Kubernetes MySQL charm, so deploy one to an IaaS model with &lt;code&gt;juju deploy cs:mysql&lt;&#x2F;code&gt;. Initialise the database as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CREATE DATABASE wordpress CHARACTER SET utf8 COLLATE utf8_unicode_ci;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CREATE USER &amp;#39;wordpress&amp;#39;@&amp;#39;%&amp;#39; IDENTIFIED BY &amp;#39;wordpress&amp;#39;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;GRANT ALL PRIVILEGES ON wordpress.* TO &amp;#39;wordpress&amp;#39;@&amp;#39;%&amp;#39;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FLUSH PRIVILEGES;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once the database is prepared we are now able to deploy the WordPress charm. The easiest way to get started with a local Kubernetes cluster is to have MicroK8s installed, reference the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git.launchpad.net&#x2F;charm-k8s-wordpress&#x2F;tree&#x2F;README.md&quot;&gt;README&lt;&#x2F;a&gt; of the charm for details on how to get one setup. Deploy the charm as follows.&lt;&#x2F;p&gt;
&lt;p&gt;Deploy the charm into your Kubernetes Juju model.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;microk8s.juju deploy cs:~wordpress-charmers&#x2F;wordpress&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The charm requires Kubernetes TLS secrets to be pre-configured to ensure logins are kept secure. Create a self-signed certificate and upload it as a Kubernetes secret.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout server.key -out server.crt&lt;&#x2F;code&gt; &lt;code&gt;microk8s.kubectl create secret tls -n wordpress tls-wordpress --cert=server.crt --key=server.key&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Tell the charm where the database is and provide some initial setup.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DB_HOST=$IP_OF_YOUR_MYSQL_DATABASE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;microk8s.juju config wordpress db_host=$DB_HOST db_user=wordpress db_password=wordpress tls_secret_name=tls-wordpress \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            initial_settings=&amp;quot;user_name: admin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            admin_email: devnull@example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            weblog_title: Test Blog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            blog_public: False&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From there you can test the site by updating your &lt;code&gt;&#x2F;etc&#x2F;hosts&lt;&#x2F;code&gt; file and creating a static entry for the IP address of the Kubernetes ingress gateway.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    App        Version                  Status   Scale  Charm      Store  Rev  OS          Address  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Messagewordpress  wordpress:bionic-stable  waiting      1  wordpress  local    0  kubernetes  10.152.183.140 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;echo &#x27;10.152.183.140 myblog.example.com&#x27; | sudo tee -a &#x2F;etc&#x2F;hosts&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It will take about 5 to 10 minutes for Juju hooks to discover the site is live and perform the initial setup for you. Look for this line in the output of &lt;code&gt;juju debug-log&lt;&#x2F;code&gt; to confirm.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;unit.wordpress&#x2F;0.juju-log Wordpress configured and initialised&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is due to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;canonical&#x2F;operator&#x2F;issues&#x2F;166&quot;&gt;issue #166&lt;&#x2F;a&gt; and will be fixed once Juju supports a Kubernetes pod ready hook.&lt;&#x2F;p&gt;
&lt;p&gt;To retrieve the random admin password, run the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;microk8s kubectl exec -ti -n wordpress wordpress-operator-0 -- cat &#x2F;root&#x2F;initial.passwd&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You should now be able to browse to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;myblog.example.com&#x2F;wp-admin&quot;&gt;https:&#x2F;&#x2F;myblog.example.com&#x2F;wp-admin&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We’ve been using this charm in production for five months now, but recently updated it to bring it up to date with a current version of the Operator Framework. We’d be interested in any feedback on the charm itself, either here or via bugs against the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bugs.launchpad.net&#x2F;charm-k8s-wordpress&quot;&gt;charm project on Launchpad&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Managing Multi Cloud Services With Juju</title>
        <published>2018-10-24T00:00:00+00:00</published>
        <updated>2018-10-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Thomas Cuthbert
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://realmofchaos.xyz/tech/managing-multi-cloud-services-with-juju/"/>
        <id>https://realmofchaos.xyz/tech/managing-multi-cloud-services-with-juju/</id>
        
        <content type="html" xml:base="https://realmofchaos.xyz/tech/managing-multi-cloud-services-with-juju/">&lt;p&gt;Managing a service with deployments in multi-cloud environments can be a challenge in terms of troubleshooting and scalability due to the complexity of dealing with different public cloud providers. An effective way to manage services deployed cross-cloud is to use tools that allow you to define your service once and deploy anywhere: in the cloud, on bare metal, or locally inside containers. In this blog post I am going to describe how the Canonical SRE team has achieved this, the tools that we use and the way we apply them to manage the Ubuntu Archive Mirror service.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;historical-archive-mirror-setup&quot;&gt;Historical Archive Mirror Setup&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;Archive-Mirror-Diagram-2.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It’s no secret that Ubuntu is a popular OS for running applications in the cloud. It was clear from the beginning that the increased adoption of Ubuntu in the cloud would cause a significant amount of stress on the master Ubuntu Archive Mirror service due to an increased rate of requests from Ubuntu instances running in public clouds. This was not a new problem for us, the Ubuntu Archive Mirror Network was originally conceived to protect the master Ubuntu Archives from getting over saturated with requests. The network architecture is a globally distributed system of web servers and caches that are operated by the community. The goal of this network is to improve response times for community users by directing traffic destined for the master Ubuntu Archive repositories to repositories geographically closer to the request’s origin. Without this distributed cache the millions of apt requests we receive every day would cause a denial of service to the master repository servers. Ubuntu updates would then be significantly degraded, which is unacceptable for any system running production grade services.&lt;&#x2F;p&gt;
&lt;p&gt;The nice thing about the Ubuntu Archive Mirror architecture is how extensible it is. Within each cloud region we have a deployment of the Ubuntu Archive Mirror service. Each regional deployment keeps in sync with the master repositories. When an Ubuntu instance is started in the cloud its apt sources are configured to point to the deployment servicing the region of which the instance is currently running. We apply this pattern to every public and private cloud we manage. This includes AWS, GCE, Azure and OpenStack.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;identifying-the-challenges&quot;&gt;Identifying the Challenges&lt;&#x2F;h1&gt;
&lt;p&gt;After understanding our architectural requirements, the next step was to figure out how to manage each individual Ubuntu Archive deployment. A non exhaustive list of challenges we needed to address were:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;How do we manage the lifecycle of each Ubuntu Archive Mirror service?&lt;&#x2F;li&gt;
&lt;li&gt;Can we be sure that each environment is consistent and that the user experience remains the same no matter which Archive Mirror environment you are working on?&lt;&#x2F;li&gt;
&lt;li&gt;How can we test proposed changes before upgrading production services?&lt;&#x2F;li&gt;
&lt;li&gt;How do we respond to incidents when things go wrong with any of our environments and how do we ensure each environment is isolated from each other to avoid unnecessary outages?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Our engineers can’t get bogged down with the semantics of each cloud. The best approach is to have a uniform interface that applies to any platform. This saves engineering time by making our playbooks more succinct and easier to digest, there is less room for error when there are minimal commands to run, a consistent UX reduces mean time to recovery as an engineer can be confident that the same troubleshooting methodology can be applied no matter which environment they are in, finally, environment specifications stored in version control allow us to keep track of changes, and easily test and rollback revisions that do not work.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-solution&quot;&gt;The Solution&lt;&#x2F;h1&gt;
&lt;p&gt;Our Ubuntu Archive mirror services are modeled with Mojo which orchestrates deployments with Juju. “Automate once, deploy anywhere” is an approach we have taken in developing our environment automation solution. We define what our environments look like once and have the tooling take care of the boring details. Juju&lt;&#x2F;p&gt;
&lt;p&gt;Juju is the component which drives each deployment. It is responsible for talking to the cloud APIs, installation and configuration of each application, provisioning cloud services, such as security, networking, storage, and user access control. Juju enables us to deploy and scale services quickly and efficiently to a variety of providers: public clouds, physical servers, OpenStack, and local containers. Juju is responsible for provisioning instances and installing the application (a charm in Juju context) onto them. It is also responsible for managing services, such as ensuring ACLs are configured, configuring advanced networking, and allocating storage.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;deployment-control&quot;&gt;Deployment Control&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;img&#x2F;mojo-brand.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;All our Archive Mirror deployments are centrally managed. We have a deployment host from which all SREs connect to environments we manage. An internally developed tool allows SREs to search for the environment they need to connect to (such as “Azure Archive Mirror for Japan East region”), and then configures for them everything they need to connect to that environment in a consistent way.&lt;&#x2F;p&gt;
&lt;p&gt;The Ubuntu Archive Mirror service itself is modeled as a Mojo specification. Mojo is a system of configuration and tools for verifying the success of Juju environment deployments. It allows us to define what an Archive Mirror is in a revision-controlled configuration repository, and a means of validating whether what we deployed is as we intended.&lt;&#x2F;p&gt;
&lt;p&gt;To deploy a new environment we use Mojo to run a manifest file which tells it which operations (phases) to perform and in what order. The manifest file looks similar to this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;collect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deploy config=services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deploy config=relations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;script config=post-deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sleep config=10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nagios-check skip-checks-extra=&amp;quot;check_ksplice,check_total_procs&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;juju-check-wait&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;verify config=verify-deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mojo recognises different phases as different actions to perform. The three main phases to be concerned about are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;collection
&lt;ul&gt;
&lt;li&gt;Mojo will download the charms (service modules) required as per the file specified in the collect call.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;deployment
&lt;ul&gt;
&lt;li&gt;The deploy phase is fairly self explanatory, it takes the artefacts from the collection phase and deploys them into the Juju model.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;verification
&lt;ul&gt;
&lt;li&gt;A script can be called once the deploy phase is complete. The script is configured to run some verification commands to make sure the deployment is in the desired state.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We define a collect file that contains an inventory of each component, known as a charm. This file looks like the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ubuntu-repository-cache lp:ubuntu-repository-cache;overwrite=True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;haproxy                 cs:haproxy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nrpe                    cs:nrpe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The actual service and relation specifications detail how each charm is related and any configuration options, i.e. Squid cache size and HAProxy monitor settings. For a look at the specification please see the appendix at the end of the post. Mojo uses codetree to pull down the charms, from either the charmstore or version control (e.g. launchpad.net or github.com), to the host and copies them to a charm repository for deployment. A phased approach protects us from incorrectly configured specifications as Mojo will not proceed if a phase fails. At the end of this process we have a new validated environment deployed and ready for use.&lt;&#x2F;p&gt;
&lt;p&gt;You can try this out for yourself, download the example mojo spec.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Before we begin you will need to have Juju, Mojo and a Juju controller bootstrapped. You can find a tutorial on how to set this up here.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Configure a Mojo project and workspace which we will use to build and test our archive mirror environment locally before it gets deployed into our cloud.&lt;&#x2F;p&gt;
&lt;p&gt;export MOJO_STAGE=production export MOJO_WORKSPACE=archive-mirror export MOJO_PROJECT=mojo-archive-mirror-proj export MOJO_SERIES=xenial export MOJO_SPEC=&lt;del&gt;&#x2F;mojo&#x2F;mojo-archive-mirror-spec&#x2F; export MOJO_LOCAL=&lt;&#x2F;del&gt;&#x2F;mojo&#x2F;LOCAL&#x2F;mojo-archive-mirror-spec&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;juju bootstrap&lt;&#x2F;p&gt;
&lt;p&gt;mkdir -p ${MOJO_SPEC}; mkdir -p ${MOJO_LOCAL}; (cd ~&#x2F;mojo; curl &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;admin.insights.ubuntu.com&#x2F;wp-content&#x2F;uploads&#x2F;db69&#x2F;mojo-archive-mirror-spec.tar.gz&quot;&gt;https:&#x2F;&#x2F;admin.insights.ubuntu.com&#x2F;wp-content&#x2F;uploads&#x2F;db69&#x2F;mojo-archive-mirror-spec.tar.gz&lt;&#x2F;a&gt; | tar xv)&lt;&#x2F;p&gt;
&lt;p&gt;mojo project-new -s $MOJO_SERIES -c lxd mojo workspace-new –project $MOJO_PROJECT -s $MOJO_SERIES $MOJO_SPEC $MOJO_WORKSPACE mojo run&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Mojo has now orchestrated a deployment of our Archive Mirror environment. Below details the instances that were created and the applications installed onto them.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ juju status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We know our new Archive Mirror is functioning because the verify phase in our manifest has curl’d the HAProxy unit and downloaded the list of supported Ubuntu series.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2018-07-16 06:53:34 [INFO] Running script verify-deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2018-07-16 06:53:35 [INFO] &#x2F;ubuntu&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;artful-backports&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;artful-proposed&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;artful-security&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;artful-updates&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;artful&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bionic-backports&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bionic-proposed&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bionic-security&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bionic-updates&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bionic&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2018-07-16 06:53:35 [INFO] Completed script verify-deploy in 0s (0.31s)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We keep track of each Archive Mirror deployment that we manage with stages embedded in the root of the Mojo spec directory. These stages are nothing more than sub-directories that Mojo looks out for. Under each stage is the information used by each Mojo phase.&lt;&#x2F;p&gt;
&lt;p&gt;The directory layout looks a little something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mojo-archive-mirror-spec # repository root.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── manifest # the manifest script, this is what mojo run is looking for.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── production&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── collect # Contains the list of charms that the collect phase will download.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── haproxy-services.yaml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── relations # Specifies the contracts between each service.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── services # Details how each service should be configured.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mojo uses this approach when sourcing local significant configuration. This comes in handy when you want to do something like configure a service with dummy credentials for the CI deployment. If we wanted to add a new stage, like ci to the list of deployments we manage, we only need to create a new directory and populate the required files:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #272822;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mojo-archive-mirror-spec&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── manifest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── production&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── collect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── collect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Any changes made to the Archive Mirror specification are tested. Our testing environment is a mixture of technologies: Jenkins, Openstack, Mojo and Juju. The testing procedure is broken down as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Jenkins job pulls the latest Mojo specification from version control.&lt;&#x2F;li&gt;
&lt;li&gt;A new juju model is created for the revision of the specification. The model is deployed into one of our private OpenStack clouds.&lt;&#x2F;li&gt;
&lt;li&gt;The Jenkins script then executes a Mojo run which deploys the Archive Mirror service to the new Juju model.&lt;&#x2F;li&gt;
&lt;li&gt;Jenkins monitors the progress and provides feedback on any errors.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This process gives us assurance that the changes we have made are deployable albeit only within an Openstack context.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;closing-comments&quot;&gt;Closing Comments&lt;&#x2F;h1&gt;
&lt;p&gt;So far our current solution has worked well. The time taken for an SRE to redeploy an Archive Mirror environment is under an hour. If an environment is sick and we start receiving alerts we can be confident that if all else fails, and troubleshooting is taking too long, we can destroy the environment and redeploy a fresh baseline. The process is as simple as failing over DNS, recreating the Juju model, running Mojo, and configuring DNS and monitoring.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
