<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://zeestrataca.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://zeestrataca.com/" rel="alternate" type="text/html" /><updated>2024-08-24T05:40:55+00:00</updated><id>http://zeestrataca.com/feed.xml</id><title type="html">Zeestrataca / Sandor Zeestraten</title><subtitle>Notes from a guy who enjoys tinkering around with computers.</subtitle><author><name>Sandor Zeestraten</name><email>sandor@zeestrataca.com</email><uri>http://zeestrataca.com</uri></author><entry><title type="html">Expanding Ceph clusters with Juju</title><link href="http://zeestrataca.com/posts/expanding-ceph-clusters-with-juju/" rel="alternate" type="text/html" title="Expanding Ceph clusters with Juju" /><published>2018-05-08T00:00:00+00:00</published><updated>2018-05-08T00:00:00+00:00</updated><id>http://zeestrataca.com/posts/expanding-ceph-clusters-with-juju</id><content type="html" xml:base="http://zeestrataca.com/posts/expanding-ceph-clusters-with-juju/"><![CDATA[<p>We just got a set of new SuperMicro servers for one of our Ceph clusters at <a href="https://www.ntnu.edu/huntgenes/hunt-cloud">HUNT Cloud</a>.
This made for a great opportunity to write up the simple steps of expanding a Ceph cluster with Juju.</p>

<p>New to Juju? <a href="https://jujucharms.com">Juju</a> is a cool controller and agent based tool from Canonical to easily deploy and manage applications (called Charms) on different clouds and environments (see <a href="https://jujucharms.com/how-it-works">how it works</a> for more details).</p>

<p>Scaling applications with Juju is easy and Ceph is no exception.
You can deploy more Ceph OSD hosts with just a simple <code class="language-plaintext highlighter-rouge">juju add-unit ceph-osd</code> command.
The challenging part is to add new OSDs without impacting client performance due to large amounts of backfilling.</p>

<p>Below is a brief walk through of the steps on how you can scale your Ceph cluster, with a small example cluster that you can deploy locally on LXD containers to follow along:</p>

<ul>
  <li>Set crush initial weight to 0</li>
  <li>Add new OSDs to the cluster</li>
  <li>Clear crush initial weight</li>
  <li>Reweight new OSDs</li>
</ul>

<h2 id="deploy-a-ceph-cluster-on-lxd-for-testing">Deploy a Ceph cluster on LXD for testing</h2>

<p>The first step is to get a Juju controller up and running so you can deploy Ceph.
If you’re new to Juju and LXD, you can get started with the official docs <a href="https://jujucharms.com/docs/stable/tut-lxd">here</a>.
In case you already have installed all the requirements, you can simply bootstrap a new controller like so:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ juju bootstrap localhost

Creating Juju controller "localhost-localhost" on localhost/localhost
Looking for packaged Juju agent version 2.3.7 for amd64
To configure your system to better support LXD containers, please see: https://github.com/lxc/lxd/blob/master/doc/production-setup.md
Launching controller instance(s) on localhost/localhost...
 - juju-a24b9d-0 (arch=amd64)
Installing Juju agent on bootstrap instance
Fetching Juju GUI 2.12.1
Waiting for address
Attempting to connect to 10.181.145.171:22
Connected to 10.181.145.171
Running machine configuration script...
Bootstrap agent now started
Contacting Juju controller at 10.181.145.171 to verify accessibility...
Bootstrap complete, "localhost-localhost" controller now available
Controller machines are in the "controller" model
Initial model "default" added
</code></pre></div></div>

<p>Next up you need to deploy the Ceph cluster.
Here’s a bundle called <a href="https://jujucharms.com/u/szeestraten/ceph-lxd/bundle"><code class="language-plaintext highlighter-rouge">ceph-lxd</code></a> which sets up a small cluster for you with:</p>

<ul>
  <li>1 Ceph Monitor host using the <a href="https://jujucharms.com/ceph-mon/"><code class="language-plaintext highlighter-rouge">ceph-mon</code></a> charm</li>
  <li>3 Ceph OSD hosts with 3 OSDs each using the <a href="https://jujucharms.com/ceph-osd/"><code class="language-plaintext highlighter-rouge">ceph-osd</code></a> charm</li>
</ul>

<p>You can deploy it straight from the Juju charm store:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ juju deploy cs:~szeestraten/bundle/ceph-lxd

Located bundle "cs:~szeestraten/bundle/ceph-lxd-1"
Resolving charm: cs:ceph-mon-24
Resolving charm: cs:ceph-osd-261
Executing changes:
- upload charm cs:ceph-mon-24 for series xenial
- deploy application ceph-mon on xenial using cs:ceph-mon-24
- set annotations for ceph-mon
- upload charm cs:ceph-osd-261 for series xenial
- deploy application ceph-osd on xenial using cs:ceph-osd-261
- set annotations for ceph-osd
- add relation ceph-osd:mon - ceph-mon:osd
- add unit ceph-mon/0 to new machine 0
- add unit ceph-osd/0 to new machine 1
- add unit ceph-osd/1 to new machine 2
- add unit ceph-osd/2 to new machine 3
Deploy of bundle completed.
</code></pre></div></div>

<p>The deployment may take a little while, so here’s your perfect chance to refill your coffee.
You can follow along with <code class="language-plaintext highlighter-rouge">juju status</code> (or <code class="language-plaintext highlighter-rouge">watch --color juju status --color</code> in case you get impatient).</p>

<p>If all goes well, you should end up with something that looks like this:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>juju status

Model    Controller  Cloud/Region  Version  SLA
default  lxd         lxd           2.3.7    unsupported

App       Version  Status  Scale  Charm     Store       Rev  OS      Notes
ceph-mon  12.2.4   active      1  ceph-mon  jujucharms   24  ubuntu
ceph-osd  12.2.4   active      3  ceph-osd  jujucharms  261  ubuntu

Unit         Workload  Agent  Machine  Public address  Ports  Message
ceph-mon/0<span class="k">*</span>  active    idle   0        10.247.146.247         Unit is ready and clustered
ceph-osd/0<span class="k">*</span>  active    idle   1        10.247.146.135         Unit is ready <span class="o">(</span>3 OSD<span class="o">)</span>
ceph-osd/1   active    idle   2        10.247.146.173         Unit is ready <span class="o">(</span>3 OSD<span class="o">)</span>
ceph-osd/2   active    idle   3        10.247.146.143         Unit is ready <span class="o">(</span>3 OSD<span class="o">)</span>

Machine  State    DNS             Inst <span class="nb">id        </span>Series  AZ  Message
0        started  10.247.146.247  juju-07321b-0  xenial      Running
1        started  10.247.146.135  juju-07321b-1  xenial      Running
2        started  10.247.146.173  juju-07321b-2  xenial      Running
3        started  10.247.146.143  juju-07321b-3  xenial      Running

Relation provider  Requirer      Interface  Type     Message
ceph-mon:mon       ceph-mon:mon  ceph       peer
ceph-mon:osd       ceph-osd:mon  ceph-osd   regular
</code></pre></div></div>

<p>Now, take a closer look at the cluster to ensure that it is in a healthy state and that all OSDs have been created:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>juju ssh ceph-mon/0 <span class="s2">"sudo -s"</span>

<span class="nv">$ </span>ceph status
  cluster:
    <span class="nb">id</span>:     f719d3e8-52ff-11e8-91f4-00163e5622ff
    health: HEALTH_OK

  services:
    mon: 1 daemons, quorum juju-07321b-0
    mgr: juju-07321b-0<span class="o">(</span>active<span class="o">)</span>
    osd: 9 osds: 9 up, 9 <span class="k">in

  </span>data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 bytes
    usage:   7367 MB used, 234 GB / 242 GB avail
    pgs:
</code></pre></div></div>

<p>The output above says that the cluster does not contain any pools, pgs or objects.
So, let’s fix that by creating a pool called <code class="language-plaintext highlighter-rouge">testpool</code> and writing some data to it with one of Ceph’s internal benchmarking tools, <code class="language-plaintext highlighter-rouge">rados bench</code>, so that we have something to actually shuffle around:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ceph osd pool create testpool 100 100
pool <span class="s1">'testpool'</span> created

<span class="nv">$ </span>ceph osd pool application <span class="nb">enable </span>testpool rgw
enabled application <span class="s1">'rgw'</span> on pool <span class="s1">'testpool'</span>

<span class="nv">$ </span>rados bench <span class="nt">-p</span> testpool 10 write <span class="nt">--no-cleanup</span>
hints <span class="o">=</span> 1
Maintaining 16 concurrent writes of 4194304 bytes to objects of size 4194304 <span class="k">for </span>up to 10 seconds or 0 objects
Object prefix: benchmark_data_juju-47966f-0_25611
  sec Cur ops   started  finished  avg MB/s  cur MB/s last lat<span class="o">(</span>s<span class="o">)</span>  avg lat<span class="o">(</span>s<span class="o">)</span>
    0       0         0         0         0         0           -           0
    1      16        36        20    79.891        80    0.934116    0.444238
    2      16        63        47   93.8659       108     1.39832    0.513196
    3      16        80        64   85.2469        68     1.32455    0.610896
    4      16       107        91   90.9015       108    0.877032    0.653832
    5      16       125       109   87.1202        72    0.218025    0.675221
    6      16       147       131   87.2638        88    0.754443     0.66334
    7      16       170       154   87.9318        92    0.645512    0.689901
    8      16       204       188   93.9318       136    0.987254    0.663071
    9      16       230       214   95.0482       104     1.37409    0.645098
   10      16       259       243   97.1393       116     1.39946    0.630096
Total <span class="nb">time </span>run:         10.306007
Total writes made:      260
Write size:             4194304
Object size:            4194304
Bandwidth <span class="o">(</span>MB/sec<span class="o">)</span>:     100.912
Stddev Bandwidth:       21.1702
Max bandwidth <span class="o">(</span>MB/sec<span class="o">)</span>: 136
Min bandwidth <span class="o">(</span>MB/sec<span class="o">)</span>: 68
Average IOPS:           25
Stddev IOPS:            5
Max IOPS:               34
Min IOPS:               17
Average Latency<span class="o">(</span>s<span class="o">)</span>:     0.630013
Stddev Latency<span class="o">(</span>s<span class="o">)</span>:      0.382552
Max latency<span class="o">(</span>s<span class="o">)</span>:         2.26802
Min latency<span class="o">(</span>s<span class="o">)</span>:         0.0696069
</code></pre></div></div>

<p>Let’s check <code class="language-plaintext highlighter-rouge">ceph status</code> once again.
You should now see the new pool and some objects created by the benchmarking tool.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ceph status
  cluster:
    <span class="nb">id</span>:     f719d3e8-52ff-11e8-91f4-00163e5622ff
    health: HEALTH_OK

  services:
    mon: 1 daemons, quorum juju-07321b-0
    mgr: juju-07321b-0<span class="o">(</span>active<span class="o">)</span>
    osd: 9 osds: 9 up, 9 <span class="k">in

  </span>data:
    pools:   1 pools, 100 pgs
    objects: 262 objects, 1044 MB
    usage:   7537 MB used, 234 GB / 241 GB avail
    pgs:     100 active+clean
</code></pre></div></div>

<p>Finally, let’s take a look at <code class="language-plaintext highlighter-rouge">ceph osd tree</code> which prints out a tree of all the OSDs according to their position in the CRUSH map.
Pay particular attention to the <code class="language-plaintext highlighter-rouge">WEIGHT</code> column as we will be manipulating these values for the new OSDs when you expand the cluster later.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ceph osd tree
ID CLASS WEIGHT  TYPE NAME              STATUS REWEIGHT PRI-AFF
-1       0.23662 root default
-3       0.07887     host juju-07321b-1
 1   hdd 0.02629         osd.1              up  1.00000 1.00000
 3   hdd 0.02629         osd.3              up  1.00000 1.00000
 6   hdd 0.02629         osd.6              up  1.00000 1.00000
-5       0.07887     host juju-07321b-2
 0   hdd 0.02629         osd.0              up  1.00000 1.00000
 4   hdd 0.02629         osd.4              up  1.00000 1.00000
 8   hdd 0.02629         osd.8              up  1.00000 1.00000
-7       0.07887     host juju-07321b-3
 2   hdd 0.02629         osd.2              up  1.00000 1.00000
 5   hdd 0.02629         osd.5              up  1.00000 1.00000
 7   hdd 0.02629         osd.7              up  1.00000 1.00000
</code></pre></div></div>

<p>Don’t worry if you don’t end up with the exact weight or usage numbers as above.
Those numbers depend on the size of storage available on the LXD host.</p>

<p>So, with a working Ceph cluster, we can finally get started.</p>

<h2 id="set-crush-initial-weight-to-0">Set crush initial weight to 0</h2>

<p>As mentioned at the top, the challenge is to manage the amount of backfilling when adding new OSDs.
One way of doing this is to make sure that all new OSDs get an initial weight of 0.
This ensures that Ceph doesn’t start shuffling around data right away when we introduce the new OSDs.</p>

<p>The <code class="language-plaintext highlighter-rouge">ceph-osd</code> charm has a handy configuration option called <a href="https://jujucharms.com/ceph-osd/#charm-config-crush-initial-weight"><code class="language-plaintext highlighter-rouge">crush-initial-weight</code></a> which allows us to set this easily across all OSDs hosts:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>juju config ceph-osd crush-initial-weight<span class="o">=</span>0
</code></pre></div></div>

<blockquote>
  <p><strong>Note:</strong> There was a <a href="https://bugs.launchpad.net/charm-ceph-osd/+bug/1764077">bug</a> in the <a href="https://jujucharms.com/ceph-osd/">ceph-osd charm</a> before revision 261 which did not render the correct configuration when setting <code class="language-plaintext highlighter-rouge">crush-initial-weight=0</code>.
Here’s a workaround for those on older revisions:</p>
  <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>juju config ceph-osd config-flags<span class="o">=</span><span class="s1">'{ "global": { "osd crush initial weight": 0 } }'</span>
</code></pre></div>  </div>
</blockquote>

<h2 id="add-new-osds-to-the-cluster">Add new OSDs to the cluster</h2>

<p>Juju makes adding new Ceph OSD hosts a breeze.
You simply tell it to add another <code class="language-plaintext highlighter-rouge">ceph-osd</code> unit and it will take care of the rest:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>juju add-unit ceph-osd
</code></pre></div></div>

<p>Time for another coffee while you wait for a new LXD container to spin up.
If all goes well, you should end up with a fourth <code class="language-plaintext highlighter-rouge">ceph-osd</code> unit in your list:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>juju status

Model    Controller  Cloud/Region  Version  SLA
default  lxd         lxd           2.3.7    unsupported

App       Version  Status  Scale  Charm     Store       Rev  OS      Notes
ceph-mon  12.2.4   active      1  ceph-mon  jujucharms   24  ubuntu
ceph-osd  12.2.4   active      4  ceph-osd  jujucharms  261  ubuntu

Unit         Workload  Agent  Machine  Public address  Ports  Message
ceph-mon/0<span class="k">*</span>  active    idle   0        10.247.146.247         Unit is ready and clustered
ceph-osd/0<span class="k">*</span>  active    idle   1        10.247.146.135         Unit is ready <span class="o">(</span>3 OSD<span class="o">)</span>
ceph-osd/1   active    idle   2        10.247.146.173         Unit is ready <span class="o">(</span>3 OSD<span class="o">)</span>
ceph-osd/2   active    idle   3        10.247.146.143         Unit is ready <span class="o">(</span>3 OSD<span class="o">)</span>
ceph-osd/3   active    idle   4        10.247.146.230         Unit is ready <span class="o">(</span>3 OSD<span class="o">)</span>

Machine  State    DNS             Inst <span class="nb">id        </span>Series  AZ  Message
0        started  10.247.146.247  juju-07321b-0  xenial      Running
1        started  10.247.146.135  juju-07321b-1  xenial      Running
2        started  10.247.146.173  juju-07321b-2  xenial      Running
3        started  10.247.146.143  juju-07321b-3  xenial      Running
4        started  10.247.146.230  juju-07321b-4  xenial      Running

Relation provider  Requirer      Interface  Type     Message
ceph-mon:mon       ceph-mon:mon  ceph       peer
ceph-mon:osd       ceph-osd:mon  ceph-osd   regular
</code></pre></div></div>

<p>Note that the new host and OSDs should get a weight of 0 in the CRUSH tree (here represented by <code class="language-plaintext highlighter-rouge">juju-07321b-4</code> and <code class="language-plaintext highlighter-rouge">osd.9</code>, <code class="language-plaintext highlighter-rouge">osd.10</code> and <code class="language-plaintext highlighter-rouge">osd.11</code>).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ceph osd tree
ID CLASS WEIGHT  TYPE NAME              STATUS REWEIGHT PRI-AFF
-1       0.23662 root default
-3       0.07887     host juju-07321b-1
 1   hdd 0.02629         osd.1              up  1.00000 1.00000
 3   hdd 0.02629         osd.3              up  1.00000 1.00000
 6   hdd 0.02629         osd.6              up  1.00000 1.00000
-5       0.07887     host juju-07321b-2
 0   hdd 0.02629         osd.0              up  1.00000 1.00000
 4   hdd 0.02629         osd.4              up  1.00000 1.00000
 8   hdd 0.02629         osd.8              up  1.00000 1.00000
-7       0.07887     host juju-07321b-3
 2   hdd 0.02629         osd.2              up  1.00000 1.00000
 5   hdd 0.02629         osd.5              up  1.00000 1.00000
 7   hdd 0.02629         osd.7              up  1.00000 1.00000
-9             0     host juju-07321b-4
 9   hdd       0         osd.9              up  1.00000 1.00000
10   hdd       0         osd.10             up  1.00000 1.00000
11   hdd       0         osd.11             up  1.00000 1.00000
</code></pre></div></div>

<blockquote>
  <p>If you only want to add OSDs (drives) to existing Ceph OSD hosts you can use the <a href="https://jujucharms.com/ceph-osd/#charm-config-osd-devices"><code class="language-plaintext highlighter-rouge">osd-devices</code></a> configuration option.
Here’s an example for this test cluster which adds a new directory as a new OSD for all <code class="language-plaintext highlighter-rouge">ceph-osd</code> hosts:</p>
  <div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>juju config ceph-osd osd-devices<span class="o">=</span><span class="s2">"/srv/osd1 /srv/osd2 /srv/osd3 /srv/osd4"</span>
</code></pre></div>  </div>
</blockquote>

<h2 id="clear-crush-initial-weight">Clear crush initial weight</h2>

<p>With all new OSDs in place, you can clear the <code class="language-plaintext highlighter-rouge">crush-initial-weight</code> configuration option we set earlier.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>juju config ceph-osd <span class="nt">--reset</span> crush-initial-weight
</code></pre></div></div>

<h2 id="reweight-new-osds">Reweight new OSDs</h2>

<p>You now need to increase the weight of the new OSDs in the CRUSH map from 0 to their target weight in order for Ceph store data on them.</p>

<p>There are a couple of different ways to go depending on how many new OSDs you have and how carefully/slowly you want to introduce them:</p>

<ul>
  <li>Reweight OSDs with <a href="http://docs.ceph.com/docs/master/man/8/ceph/#commands"><code class="language-plaintext highlighter-rouge">ceph osd crush reweight &lt;name&gt; &lt;weight&gt;</code></a>
    <ul>
      <li>Good for individual or small amounts of OSDs</li>
    </ul>
  </li>
  <li>Reweight subtrees <a href="http://docs.ceph.com/docs/master/man/8/ceph/#commands"><code class="language-plaintext highlighter-rouge">ceph osd crush reweight-subtree &lt;name&gt; &lt;weight&gt;</code></a>
    <ul>
      <li>Good for larger amount of OSDs under a bucket (such as <code class="language-plaintext highlighter-rouge">host</code>, <code class="language-plaintext highlighter-rouge">chassis</code>, <code class="language-plaintext highlighter-rouge">rack</code> etc.)</li>
    </ul>
  </li>
  <li>Gently reweight a list of OSDs with <a href="https://github.com/cernceph/ceph-scripts/blob/master/tools/ceph-gentle-reweight"><code class="language-plaintext highlighter-rouge">ceph-gentle-reweight</code></a>, a tool from the folks at CERN
    <ul>
      <li>Good for gradually adding/removing a list of OSDs and want to limit disruption by monitoring latency and backfilling</li>
    </ul>
  </li>
  <li><a href="http://docs.ceph.com/docs/master/rados/operations/crush-map-edits/">Manually editing the CRUSH map</a>
    <ul>
      <li>Good for manually controlling the CRUSH map with automation, version control etc.</li>
    </ul>
  </li>
</ul>

<p>The main point is that you want to increment the weight of the OSDs in small steps in order to control the amount of backfilling Ceph will have to do.
As with all things Ceph, this will of course depend on your cluster so I highly recommended you try these things in a staging cluster and start small.</p>

<p>For our test, let’s use the <code class="language-plaintext highlighter-rouge">reweight-subtree</code> command with a weight of <code class="language-plaintext highlighter-rouge">0.01</code> so we can reweight all the OSDs of the new Ceph OSD host:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ceph osd crush reweight-subtree juju-07321b-4 0.01
reweighted subtree <span class="nb">id</span> <span class="nt">-9</span> name <span class="s1">'juju-07321b-4'</span> to 0.01 <span class="k">in </span>crush map
</code></pre></div></div>

<p>While Ceph is working, keep an eye on the CRUSH tree and the disk usage with this command:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ceph osd df tree
ID CLASS WEIGHT  REWEIGHT SIZE   USE    AVAIL  %USE VAR  PGS TYPE NAME
-1       0.26660        -   316G 10012M   306G 3.09 1.00   - root default
-3       0.07887        - 80948M  2509M 78439M 3.10 1.00   -     host juju-07321b-1
 1   hdd 0.02629  1.00000 26982M   836M 26146M 3.10 1.00  26         osd.1
 3   hdd 0.02629  1.00000 26983M   836M 26146M 3.10 1.00  27         osd.3
 6   hdd 0.02629  1.00000 26983M   836M 26146M 3.10 1.00  31         osd.6
-5       0.07887        - 80947M  2507M 78439M 3.10 1.00   -     host juju-07321b-2
 0   hdd 0.02629  1.00000 26982M   835M 26146M 3.10 1.00  24         osd.0
 4   hdd 0.02629  1.00000 26982M   835M 26146M 3.10 1.00  24         osd.4
 8   hdd 0.02629  1.00000 26982M   835M 26146M 3.10 1.00  32         osd.8
-7       0.07887        - 80951M  2511M 78439M 3.10 1.00   -     host juju-07321b-3
 2   hdd 0.02629  1.00000 26983M   837M 26146M 3.10 1.00  20         osd.2
 5   hdd 0.02629  1.00000 26983M   837M 26146M 3.10 1.00  41         osd.5
 7   hdd 0.02629  1.00000 26983M   837M 26146M 3.10 1.00  29         osd.7
-9       0.02998        - 80923M  2483M 78439M 3.07 0.99   -     host juju-07321b-4
 9   hdd 0.00999  1.00000 26974M   827M 26146M 3.07 0.99  10         osd.9
10   hdd 0.00999  1.00000 26974M   827M 26146M 3.07 0.99  13         osd.10
11   hdd 0.00999  1.00000 26974M   827M 26146M 3.07 0.99  23         osd.11
                    TOTAL   316G 10012M   306G 3.09
MIN/MAX VAR: 0.99/1.00  STDDEV: 0.01
</code></pre></div></div>

<p>As you can see, the new weight of the new OSDs <code class="language-plaintext highlighter-rouge">osd.9</code>, <code class="language-plaintext highlighter-rouge">osd.10</code> and <code class="language-plaintext highlighter-rouge">osd.11</code> is <code class="language-plaintext highlighter-rouge">~0.01</code>.</p>

<p>Again, for real clusters, reweighting in multiple small steps is what will take most of the time and what you really want to automate.</p>

<p>To keep this short, let’s reweight the OSDs again, this time directly to the target weight of the original OSDs:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ceph osd crush reweight-subtree juju-07321b-4 0.026299
reweighted subtree id -9 name 'juju-07321b-4' to 0.026299 in crush map

$ ceph osd df tree
ID CLASS WEIGHT  REWEIGHT SIZE   USE    AVAIL  %USE VAR  PGS TYPE NAME
-1       0.31549        -   316G 10029M   306G 3.10 1.00   - root default
-3       0.07887        - 80931M  2509M 78421M 3.10 1.00   -     host juju-07321b-1
 1   hdd 0.02629  1.00000 26977M   836M 26140M 3.10 1.00  25         osd.1
 3   hdd 0.02629  1.00000 26977M   836M 26140M 3.10 1.00  26         osd.3
 6   hdd 0.02629  1.00000 26977M   836M 26140M 3.10 1.00  25         osd.6
-5       0.07887        - 80927M  2505M 78421M 3.10 1.00   -     host juju-07321b-2
 0   hdd 0.02629  1.00000 26975M   835M 26140M 3.10 1.00  20         osd.0
 4   hdd 0.02629  1.00000 26975M   835M 26140M 3.10 1.00  23         osd.4
 8   hdd 0.02629  1.00000 26975M   835M 26140M 3.10 1.00  22         osd.8
-7       0.07887        - 80933M  2511M 78421M 3.10 1.00   -     host juju-07321b-3
 2   hdd 0.02629  1.00000 26977M   837M 26140M 3.10 1.00  21         osd.2
 5   hdd 0.02629  1.00000 26977M   837M 26140M 3.10 1.00  33         osd.5
 7   hdd 0.02629  1.00000 26977M   837M 26140M 3.10 1.00  27         osd.7
-9       0.07887        - 80925M  2503M 78421M 3.09 1.00   -     host juju-07321b-4
 9   hdd 0.02629  1.00000 26975M   834M 26140M 3.09 1.00  25         osd.9
10   hdd 0.02629  1.00000 26975M   834M 26140M 3.09 1.00  21         osd.10
11   hdd 0.02629  1.00000 26975M   834M 26140M 3.09 1.00  32         osd.11
                    TOTAL   316G 10029M   306G 3.10
MIN/MAX VAR: 1.00/1.00  STDDEV: 0.00
</code></pre></div></div>

<p>And there you go.
All the new OSDs have been introduced to the cluster and weighted correctly.</p>

<h2 id="afterword">Afterword</h2>

<p>Thanks to all the <a href="https://docs.openstack.org/charm-guide/latest/index.html">OpenStack Charmers</a> for creating and keeping all of these charms in great shape.
Also thanks to Dan van der Ster and the storage folks at CERN for the tools and many great tips on how to run Ceph at scale.
Finally, many thanks to Oddgeir Lingaas Holmen for helping write and clean up these posts.</p>]]></content><author><name>Sandor Zeestraten</name><email>sandor@zeestrataca.com</email><uri>http://zeestrataca.com</uri></author><category term="posts" /><category term="juju" /><category term="ceph" /><summary type="html"><![CDATA[How to easily scale your Ceph cluster with Juju with minimal performance impact]]></summary></entry><entry><title type="html">Upgrading Juju</title><link href="http://zeestrataca.com/posts/upgrading-juju/" rel="alternate" type="text/html" title="Upgrading Juju" /><published>2018-03-28T00:00:00+00:00</published><updated>2018-03-28T00:00:00+00:00</updated><id>http://zeestrataca.com/posts/upgrading-juju</id><content type="html" xml:base="http://zeestrataca.com/posts/upgrading-juju/"><![CDATA[<p>I recently spent some time upgrading our Juju environments from 2.1 to 2.3. Below are a few lessons learned aimed at other Juju enthusiasts doing the same experiment.</p>

<p>First, <a href="https://jujucharms.com">Juju</a> is a cool controller and agent based tool from Canonical to easily deploy and manage applications (called Charms) on different clouds and environments (see <a href="https://jujucharms.com/how-it-works">how it works</a> for more details).</p>

<p>We run an academic cloud, <a href="https://www.ntnu.edu/huntgenes/hunt-cloud">HUNT Cloud</a>, where we utilize a highly available Juju deployment, in concert with <a href="https://maas.io">MAAS</a>, to run things like <a href="https://www.openstack.org">OpenStack</a> and <a href="https://ceph.com">Ceph</a>. For this upgrade, we were looking forward to some of the new features such as cross model relations and overlay bundles.</p>

<h2 id="how-to-upgrade-juju-for-dummies">How to upgrade Juju (for dummies)</h2>

<p>Upgrading a Juju environment is usually a straightforward task completed with a cup of coffee and a couple of commands. The main steps are:</p>

<ol>
  <li>Upgrade your Juju client (the client talking to the Juju controllers, usually on your local machine, <code class="language-plaintext highlighter-rouge">apt upgrade juju</code> or <code class="language-plaintext highlighter-rouge">snap refresh juju</code>)</li>
  <li>Upgrade your Juju controller (the controller managing the agents, <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model controller</code>)</li>
  <li>Upgrade your Juju model (the model containing your deployed applications, <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model &lt;name-of-model&gt;</code>)</li>
</ol>

<blockquote>
  <p>Check out the <a href="https://jujucharms.com/docs/stable/models-upgrade">official docs</a> for a more thorough explanation.</p>
</blockquote>

<p>Our task at hand was to upgrade the Juju environment from 2.1.2 to 2.3.
Step 1 was easy as can be, however the remaining steps provided a few lessons learned that might prove useful for others.</p>

<h2 id="issue-no-1">Issue No. 1</h2>

<p>We ran the following command to upgrade our controllers:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>juju upgrade-juju <span class="nt">--model</span> controller
best version:
    2.2.9
started upgrade to 2.2.9
</code></pre></div></div>

<p>Now, if you look closely, the output above says 2.2.9, not 2.3.2 which was the latest version at the time and the one I actually wanted.
Well, the upgrade to 2.2.9 succeeded, so I continued upgrading once more by running <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model controller</code> to reach 2.3.2.</p>

<p>This time things didn’t go as smooth for the controllers and they got stuck upgrading which rendered the environment unusable.
It did however produce some rather bleak yet humorous error messages.</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2018-01-30 11:15:22 WARNING juju.worker.upgradesteps worker.go:275 stopped waiting <span class="k">for </span>other controllers: tomb: dying
2018-01-30 11:15:22 ERROR juju.worker.upgradesteps worker.go:379 upgrade from 2.2.9 to 2.3.2 <span class="k">for</span> <span class="s2">"machine-0"</span> failed <span class="o">(</span>giving up<span class="o">)</span>: tomb: dying
</code></pre></div></div>

<p>I was able to reproduce this in one of our larger staging areas and the bug got fixed  in 2.3.3 in <a href="https://bugs.launchpad.net/juju/+bug/1746265">lp#1746265</a>.</p>

<h2 id="issue-no-2">Issue No. 2</h2>

<p>So, after getting stuck with the issue above, I was encouraged to try upgrading straight to 2.3.2, skipping 2.2.9 altogether.
Juju allows you to specify the target version using the <code class="language-plaintext highlighter-rouge">--agent-version</code> flag.
The command you end up with is <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model controller --agent-version 2.3.2</code>.</p>

<p>Sticking to good form and the rule of three, the controllers got stuck upgrading rendering the environment unusable once again.
Fortunately, it was easy to reproduce both in our staging area and on local LXD deployments so this one also got fixed in 2.3.3 in <a href="https://bugs.launchpad.net/juju/+bug/1748294">lp#1748294</a>.</p>

<h2 id="issue-no-3">Issue no. 3</h2>

<p>We gave the upgrade a new try when version 2.3.4 rolled around late in February.
Things looked good after multiple runs in staging, so I finally upgraded one of our production controllers using <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model controller --agent-version 2.3.4</code>.</p>

<p>The upgrade process took around 15 minutes. After a lot of logspam in the controller logs and some unnerving error messages in the <code class="language-plaintext highlighter-rouge">juju status --model controller</code> output, things seemed to settle.
Almost.
We noticed charm agent failures and connection errors between the controllers and a small number of the applications in the main production Juju model containing our OpenStack and Ceph deployments.</p>

<p>After filing <a href="https://bugs.launchpad.net/juju/+bug/1755155">lp#1755155</a>, I was recommended to push on and upgrade the Juju model even though some of the charms errored out.
This approach resolved the connection errors.</p>

<p>The root cause was most likely <a href="https://bugs.launchpad.net/juju/+bug/1697936">lp#1697936</a> which was reported last year.
It turned out 2.1 agents could fail to read from 2.2 and newer controllers.
I did eventually find a mention of the bug in the changelog for 2.2.0, however the description did not contain the error messages leaving my searches in Launchpad coming up empty.</p>

<p>Upgrading the model with <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model openstack --agent-version 2.3.4</code> and restarting the affected agents finally did the trick and all components were running smoothly on 2.3.4.</p>

<h2 id="afterword">Afterword</h2>

<p>To be fair to the Juju team, our production model has a decent amount of different charms and therefore a decent amount of Juju agents (<a href="https://checknotes.files.wordpress.com/2016/01/openstack-logical-arch-folsom.png?w=1280">we are talking about OpenStack after all</a>).</p>

<p>Now you might rightfully ask, <em>Sandor, why on earth didn’t you just upgrade the model right away as described in step 3?</em>
Well, I simply became a bit wary of proceeding without any easy way to rollback after running into all the previous bugs where things got stuck.</p>

<h2 id="lessons-learned">Lessons learned</h2>

<ul>
  <li>Always read the changelogs. Carefully.</li>
  <li>Always test the upgrades. This goes both for users and the dev team.</li>
  <li>The upgrade UX has room for improvements with everything from <code class="language-plaintext highlighter-rouge">apt upgrade juju</code>, <code class="language-plaintext highlighter-rouge">snap refresh juju</code>. <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model controller</code>, <code class="language-plaintext highlighter-rouge">juju upgrade-juju --model model</code>, <code class="language-plaintext highlighter-rouge">juju upgrade-charm</code> to <code class="language-plaintext highlighter-rouge">juju upgrade-gui</code>.</li>
  <li>As things can go awry, it would be nice if <code class="language-plaintext highlighter-rouge">juju upgrade-juju</code> would tell you what it will do without the <code class="language-plaintext highlighter-rouge">--dry-run</code> flag as it may not pick the version you want.</li>
  <li>It would also be nice if there was a way to do proper dry runs or even rollback (both failed and successful) upgrades besides backing up and restoring your controllers.</li>
  <li>Even though the controller and the model are upgraded separately and should be able to run different versions, they can break each other.</li>
</ul>

<p>Many thanks to Rick, Tim, John and the rest of the Juju gang from Canonical for helping out with tips, troubleshooting and fixes.</p>]]></content><author><name>Sandor Zeestraten</name><email>sandor@zeestrataca.com</email><uri>http://zeestrataca.com</uri></author><category term="posts" /><category term="juju" /><summary type="html"><![CDATA[Experiences upgrading highly available Juju environments from 2.1 to 2.3]]></summary></entry></feed>