Skip to content

Latest commit

 

History

History

CAA 2

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>

<meta charset="utf-8">
<meta name="generator" content="quarto-1.3.450">

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">

<meta name="author" content="Alejandro Pérez Bueno">

<title>CAT 2</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
  width: 0.8em;
  margin: 0 0.8em 0.2em -1em; /* quarto-specific, see quarto-dev/quarto-cli#4556 */ 
  vertical-align: middle;
}
/* CSS for syntax highlighting */
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
  { counter-reset: source-line 0; }
pre.numberSource code > span
  { position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
  { content: counter(source-line);
    position: relative; left: -1em; text-align: right; vertical-align: baseline;
    border: none; display: inline-block;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
  }
pre.numberSource { margin-left: 3em;  padding-left: 4px; }
div.sourceCode
  {   }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
</style>


<script src="README_files/libs/clipboard/clipboard.min.js"></script>
<script src="README_files/libs/quarto-html/quarto.js"></script>
<script src="README_files/libs/quarto-html/popper.min.js"></script>
<script src="README_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="README_files/libs/quarto-html/anchor.min.js"></script>
<link href="README_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="README_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="README_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="README_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="README_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">


</head>

<body>

<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<div id="quarto-margin-sidebar" class="sidebar margin-sidebar">
  <nav id="TOC" role="doc-toc" class="toc-active">
    <h2 id="toc-title">Table of Contents</h2>
   
  <ul>
  <li><a href="#exercise-1" id="toc-exercise-1" class="nav-link active" data-scroll-target="#exercise-1">Exercise 1</a>
  <ul class="collapse">
  <li><a href="#basic-vm-configuration" id="toc-basic-vm-configuration" class="nav-link" data-scroll-target="#basic-vm-configuration">Basic VM configuration</a></li>
  <li><a href="#set-up-web-service" id="toc-set-up-web-service" class="nav-link" data-scroll-target="#set-up-web-service">Set up web service</a></li>
  </ul></li>
  <li><a href="#exercise-2" id="toc-exercise-2" class="nav-link" data-scroll-target="#exercise-2">Exercise 2</a>
  <ul class="collapse">
  <li><a href="#basic-vm-configuration-1" id="toc-basic-vm-configuration-1" class="nav-link" data-scroll-target="#basic-vm-configuration-1">Basic VM configuration</a></li>
  <li><a href="#frontend-setup" id="toc-frontend-setup" class="nav-link" data-scroll-target="#frontend-setup">Frontend setup</a></li>
  <li><a href="#workers-setup" id="toc-workers-setup" class="nav-link" data-scroll-target="#workers-setup">Workers setup</a></li>
  <li><a href="#testing-the-results" id="toc-testing-the-results" class="nav-link" data-scroll-target="#testing-the-results">Testing the results</a></li>
  </ul></li>
  <li><a href="#exercise-3" id="toc-exercise-3" class="nav-link" data-scroll-target="#exercise-3">Exercise 3</a>
  <ul class="collapse">
  <li><a href="#basic-vm-configuration-2" id="toc-basic-vm-configuration-2" class="nav-link" data-scroll-target="#basic-vm-configuration-2">Basic VM configuration</a></li>
  </ul></li>
  <li><a href="#annex" id="toc-annex" class="nav-link" data-scroll-target="#annex">Annex</a></li>
  </ul>
<div class="quarto-alternate-formats"><h2>Other Formats</h2><ul><li><a href="README.md"><i class="bi bi-file-code"></i>Github (GFM)</a></li><li><a href="README.pdf"><i class="bi bi-file-pdf"></i>PDF</a></li></ul></div></nav>
</div>
<main class="content" id="quarto-document-content">

<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
<h1 class="title">CAT 2</h1>
<p class="subtitle lead">Cloud Computing</p>
</div>



<div class="quarto-title-meta">

    <div>
    <div class="quarto-title-meta-heading">Author</div>
    <div class="quarto-title-meta-contents">
             <p>Alejandro Pérez Bueno </p>
          </div>
  </div>
    
    <div>
    <div class="quarto-title-meta-heading">Published</div>
    <div class="quarto-title-meta-contents">
      <p class="date">Jan 03, 2024</p>
    </div>
  </div>
  
    
  </div>
  

</header>

<div style="page-break-after: always;"></div>
<section id="exercise-1" class="level2">
<h2 class="anchored" data-anchor-id="exercise-1">Exercise 1</h2>
<section id="basic-vm-configuration" class="level3">
<h3 class="anchored" data-anchor-id="basic-vm-configuration">Basic VM configuration</h3>
<p>First and foremost, it is necessary to create the VM and access it with SSH:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">ssh</span> <span class="at">-i</span> .ssh/id_rsa root@84.88.58.81 <span class="at">-p</span> 55000</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>In order to configure the VM with minimal configuration, one must do the following (as <em>root</em>):</p>
<div class="sourceCode" id="annotated-cell-2"><pre class="sourceCode bash code-annotation-code code-with-copy code-annotated"><code class="sourceCode bash"><a class="code-annotation-anchor" data-target-cell="annotated-cell-2" data-target-annotation="1" onclick="event.preventDefault();" href="">1</a><span id="annotated-cell-2-1" class="code-annotation-target"><a href="#annotated-cell-2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">apt</span> update <span class="kw">&amp;&amp;</span> <span class="ex">apt</span> upgrade <span class="at">-y</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-2" data-target-annotation="2" onclick="event.preventDefault();" href="">2</a><span id="annotated-cell-2-2" class="code-annotation-target"><a href="#annotated-cell-2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">hostnamectl</span> set-hostname tux</span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-2" data-target-annotation="3" onclick="event.preventDefault();" href="">3</a><span id="annotated-cell-2-3" class="code-annotation-target"><a href="#annotated-cell-2-3" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="st">"127.0.0.1 tux.ccuoc.org tux"</span> <span class="op">&gt;&gt;</span> /etc/hosts</span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-2" data-target-annotation="4" onclick="event.preventDefault();" href="">4</a><span id="annotated-cell-2-4" class="code-annotation-target"><a href="#annotated-cell-2-4" aria-hidden="true" tabindex="-1"></a><span class="ex">apt</span> install nginx apache2-utils jmeter <span class="at">-y</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-2" data-target-annotation="1">1</dt>
<dd>
<span data-code-annotation="1" data-code-cell="annotated-cell-2" data-code-lines="1">Update the system.</span>
</dd>
<dt data-target-cell="annotated-cell-2" data-target-annotation="2">2</dt>
<dd>
<span data-code-annotation="2" data-code-cell="annotated-cell-2" data-code-lines="2">Set hostname to <code>tux</code>.</span>
</dd>
<dt data-target-cell="annotated-cell-2" data-target-annotation="3">3</dt>
<dd>
<span data-code-annotation="3" data-code-cell="annotated-cell-2" data-code-lines="3">Change domain to <code>ccuog.org</code>.</span>
</dd>
<dt data-target-cell="annotated-cell-2" data-target-annotation="4">4</dt>
<dd>
<span data-code-annotation="4" data-code-cell="annotated-cell-2" data-code-lines="4">Install <code>nginx</code>, <code>apache2-utils</code> and <code>jmeter</code>.</span>
</dd>
</dl>
<p>Now everything has been set up (see <a href="#fig-minimal-config">Figure&nbsp;1</a>).</p>
</section>
<section id="set-up-web-service" class="level3">
<h3 class="anchored" data-anchor-id="set-up-web-service">Set up web service</h3>
<p>The website I created is a web version of the first practice I submitted (I write them in <code>quarto</code>, a markdown tool that does wonders for these kinds of assignments). It is fairly complex as it has custom images, code formatting, sidebars and other non-textual content.</p>
<p>First, copy the website and its files to the <code>/var/www/html</code> directory:</p>
<div class="sourceCode" id="annotated-cell-3"><pre class="sourceCode bash code-annotation-code code-with-copy code-annotated"><code class="sourceCode bash"><a class="code-annotation-anchor" data-target-cell="annotated-cell-3" data-target-annotation="1" onclick="event.preventDefault();" href="">1</a><span id="annotated-cell-3-1" class="code-annotation-target"><a href="#annotated-cell-3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">cp</span> README.html /var/www/html/index.html</span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-3" data-target-annotation="2" onclick="event.preventDefault();" href="">2</a><span id="annotated-cell-3-2" class="code-annotation-target"><a href="#annotated-cell-3-2" aria-hidden="true" tabindex="-1"></a><span class="fu">cp</span> <span class="at">-r</span> README_files/ /var/www/html/</span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-3" data-target-annotation="3" onclick="event.preventDefault();" href="">3</a><span id="annotated-cell-3-3" class="code-annotation-target"><a href="#annotated-cell-3-3" aria-hidden="true" tabindex="-1"></a><span class="fu">cp</span> <span class="at">-r</span> img /var/www/html/</span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-3" data-target-annotation="1">1</dt>
<dd>
<span data-code-annotation="1" data-code-cell="annotated-cell-3" data-code-lines="1">Main <em>HTML</em> file.</span>
</dd>
<dt data-target-cell="annotated-cell-3" data-target-annotation="2">2</dt>
<dd>
<span data-code-annotation="2" data-code-cell="annotated-cell-3" data-code-lines="2">Extra files from quarto to make the website pretty.</span>
</dd>
<dt data-target-cell="annotated-cell-3" data-target-annotation="3">3</dt>
<dd>
<span data-code-annotation="3" data-code-cell="annotated-cell-3" data-code-lines="3">Images from screenshots I made in the previous CAA.</span>
</dd>
</dl>
<p>Then start the <code>nginx</code> service:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">systemctl</span> enable <span class="at">--now</span> nginx</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>At this point our website is up and running! We can check that it is working with <code>ab</code> (ApacheBenchmark) and with <code>JMeter</code> (see <a href="#fig-test-ab-jmeter-ex1">Figure&nbsp;2</a>).</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Note
</div>
</div>
<div class="callout-body-container callout-body">
<p>Note how in the command from <a href="#fig-test-ab-ex1">Figure&nbsp;2 (a)</a> I did not specify the IP of VM, but the domain. This is merely to prove that it is possible to open the website this way too.</p>
</div>
</div>
<p>You can also simply open a browser on your local machine and enter the IP of the Remote (see <a href="#fig-website">Figure&nbsp;3</a>).</p>
<div style="page-break-after: always;"></div>
</section>
</section>
<section id="exercise-2" class="level2">
<h2 class="anchored" data-anchor-id="exercise-2">Exercise 2</h2>
<section id="basic-vm-configuration-1" class="level3">
<h3 class="anchored" data-anchor-id="basic-vm-configuration-1">Basic VM configuration</h3>
<div class="callout callout-style-default callout-warning callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Warning
</div>
</div>
<div class="callout-body-container callout-body">
<p>The VM from the previous exercise has been deleted, so nothing from the previous exercise will be reused in this one.</p>
</div>
</div>
<p>Three VMs have to be configured:</p>
<ol type="1">
<li>A machine called <code>frontend</code> with a private and a public NIC.</li>
<li>A machine called <code>worker1</code> with a private NIC.</li>
<li>A machine called <code>worker2</code> with a private NIC.</li>
</ol>
<p>On all of them, we have to do the following:</p>
<ul>
<li>Update packages and install <code>apache2</code>.</li>
<li>Set hostname and the hosts file appropriately following the same scheme as in the prior exercise.</li>
<li>Specify the private IPs and domain names for the other VMs in all three machines, as follows:</li>
</ul>
<div class="sourceCode" id="cb3"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">192.168.0.7</span> frontend</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">192.168.0.8</span> worker1</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">192.168.0.6</span> worker2</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>You can see how I have set up these VMs in OpenNebula (see <span class="citation" data-cites="on-vms-ex2">@on-vms-ex2</span>).</p>
</section>
<section id="frontend-setup" class="level3">
<h3 class="anchored" data-anchor-id="frontend-setup">Frontend setup</h3>
<p>Edit the configuration file <code>/etc/apache2/sites-available/000-default.conf</code> adding the following lines inside the <code>VirtualHost</code> section:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span>Proxy <span class="ex">balancer://mycluster</span><span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="ex">BalancerMember</span> http://worker1:80</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="ex">BalancerMember</span> http://worker2:80</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="ex">ProxySet</span> lbmethod=byrequests <span class="co"># or ProxySet lbmethod=bytraffic</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span>/Proxy<span class="op">&gt;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="ex">ProxyPass</span> /balancer-manager !</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="ex">ProxyPass</span> / balancer://mycluster/</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="ex">ProxyPassReverse</span> / http://frontend.ccuoc.org/</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="ex">ProxyPreserveHost</span> On</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span>Location <span class="ex">/balancer-manager</span><span class="op">&gt;</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="ex">SetHandler</span> balancer-manager</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="op">&lt;</span>/Location<span class="op">&gt;</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>This configuration sets a balancer for the two websites hosted on the worker VMs with a certain balancer algorithm (installed as a module using <code>a2enmod</code>). It also enables the use of the <code>balancer-manager</code> extension.</p>
</section>
<section id="workers-setup" class="level3">
<h3 class="anchored" data-anchor-id="workers-setup">Workers setup</h3>
<p>Copy the different websites and their necessary files to each of the worker VMs’ <code>/var/www/html</code> directory. For this I picked the following:</p>
<ul>
<li>For <code>worker1</code> VM: Same site from the previous website.</li>
<li>For <code>worker2</code> VM: Similar site from another project.</li>
</ul>
</section>
<section id="testing-the-results" class="level3">
<h3 class="anchored" data-anchor-id="testing-the-results">Testing the results</h3>
<p>Once all 3 VMs are up and running, let’s make sure that they all three have the <code>apache</code> service started and updated to the latest changes made in the configuration files. To do so, we will restart the server:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">systemctl</span> enable apache2</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ex">systemctl</span> restart apache2</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>Then, using <code>ab</code> like in the previous exercise we can benchmark the two balancing algorithms we are to compare:</p>
<ul>
<li><code>byrequests</code>: distributes traffic evenly to every worker. In this case it would be <code>50</code>/<code>50</code>.</li>
<li><code>bytraffic</code>: distributes the workload based on the load of each worker.</li>
</ul>
<p>We will compare the two algorithms by running the following command:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">ab</span> <span class="at">-n</span> 100 <span class="at">-c</span> 10 <span class="op">&lt;</span>FrontendPublicIP<span class="op">&gt;</span>/</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<ul>
<li><code>ab</code>: The same apache utility used in exercise 1.</li>
<li><code>-n 100</code>: number of petitions made to the server.</li>
<li><code>-c 10</code>: number of <em>concurrent</em> requests made to the server at a time.</li>
</ul>
<p>As can be seen in the screenshots from <a href="#fig-lbmethod">Figure&nbsp;4</a>, <code>bytraffic</code> is more efficient at distributing higher workloads, since fewer requests are lost when compared to the <code>byrequests</code> algorithm.</p>
<p>You can also verify that the balancer located at <code>http://&lt;FrontendPublicIP&gt;/balancer-manager</code> is working (see <a href="#fig-balancer-manager">Figure&nbsp;5</a>), and that both sites are served in the frontend (see <a href="#fig-pages-ex2">Figure&nbsp;6</a>).</p>
<div style="page-break-after: always;"></div>
</section>
</section>
<section id="exercise-3" class="level2">
<h2 class="anchored" data-anchor-id="exercise-3">Exercise 3</h2>
<div class="callout callout-style-default callout-warning callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Warning
</div>
</div>
<div class="callout-body-container callout-body">
<p>For the third exercise, I reused some of the previous configurations. Here is what has changed in the setup:</p>
<ul>
<li>Recreated <code>frontend</code>, without setting up Proxy (I kept running out of space when installing <code>docker</code>).</li>
<li>Reused <code>worker1</code>.</li>
<li>Deleted <code>worker2</code>.</li>
</ul>
</div>
</div>
<section id="basic-vm-configuration-2" class="level3">
<h3 class="anchored" data-anchor-id="basic-vm-configuration-2">Basic VM configuration</h3>
<p>Let’s begin by installing <code>docker</code> on both VMs. According to the <a href="https://docs.docker.com/engine/install/debian/">docker documentation</a>, we must enter the following commands:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Add Docker's official GPG key:</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt-get update</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt-get install ca-certificates curl gnupg</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> install <span class="at">-m</span> 0755 <span class="at">-d</span> /etc/apt/keyrings</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="ex">curl</span> <span class="at">-fsSL</span> https://download.docker.com/linux/debian/gpg <span class="kw">|</span> <span class="dt">\</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>  <span class="fu">sudo</span> gpg <span class="at">--dearmor</span> <span class="at">-o</span> /etc/apt/keyrings/docker.gpg</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> chmod a+r /etc/apt/keyrings/docker.gpg</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="co"># Add the repository to Apt sources:</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="bu">echo</span> <span class="dt">\</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>  <span class="st">"deb [arch=</span><span class="va">$(</span><span class="ex">dpkg</span> <span class="at">--print-architecture</span><span class="va">)</span><span class="st"> </span><span class="dt">\</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="st">    signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian </span><span class="dt">\</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a><span class="st">  </span><span class="va">$(</span><span class="bu">.</span> /etc/os-release <span class="kw">&amp;&amp;</span> <span class="bu">echo</span> <span class="st">"</span><span class="va">$VERSION_CODENAME</span><span class="st">"</span><span class="va">)</span><span class="st"> stable"</span> <span class="kw">|</span> <span class="dt">\</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>  <span class="fu">sudo</span> tee /etc/apt/sources.list.d/docker.list <span class="op">&gt;</span> /dev/null</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt-get update</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>And then install <code>docker</code> and other related utilities:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="fu">sudo</span> apt-get install docker-ce docker-ce-cli containerd.io <span class="dt">\</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  docker-buildx-plugin docker-compose-plugin</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>To set up a <code>swarm</code> in <code>docker</code>, you can do the following on the <code>frontend</code> V:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> swarm init <span class="at">--advertise-addr</span> 192.168.0.25</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>This gives you a token that can be used on the <code>worker</code> VM as follows:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">docker</span> swarm join <span class="at">--token</span> <span class="op">&lt;</span>token<span class="op">&gt;</span> 192.168.0.25:2377</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div style="page-break-after: always;"></div>
</section>
</section>
<section id="annex" class="level2">
<h2 class="anchored" data-anchor-id="annex">Annex</h2>
<div id="fig-minimal-config" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/vm-minimal-ex1.png" class="img-fluid figure-img" style="width:70.0%"></p>
<figcaption class="figure-caption">Figure&nbsp;1: Minimal VM Configuration</figcaption>
</figure>
</div>
<div id="fig-test-ab-jmeter-ex1" class="quarto-layout-panel">
<figure class="figure">
<div class="quarto-layout-row quarto-layout-valign-top">
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-test-ab-ex1" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/ab-test-ex1.png" class="img-fluid figure-img" data-ref-parent="fig-test-ab-jmeter-ex1"></p>
<figcaption class="figure-caption">(a) <code>ab</code></figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-test-jmeter-ex1" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/jmeter-test-ex1.png" class="img-fluid figure-img" data-ref-parent="fig-test-ab-jmeter-ex1"></p>
<figcaption class="figure-caption">(b) <code>JMeter</code></figcaption>
</figure>
</div>
</div>
</div>
<p></p><figcaption class="figure-caption">Figure&nbsp;2: Test that the site is running with <code>ab</code> and <code>JMeter</code></figcaption><p></p>
</figure>
</div>
<div id="fig-website" class="quarto-layout-panel">
<figure class="figure">
<div class="quarto-layout-row quarto-layout-valign-top">
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-website-top" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/website-test-1-ex1.png" class="img-fluid figure-img" data-ref-parent="fig-website"></p>
<figcaption class="figure-caption">(a) Site top</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-website-image" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/website-test-2-ex1.png" class="img-fluid figure-img" data-ref-parent="fig-website"></p>
<figcaption class="figure-caption">(b) Site image</figcaption>
</figure>
</div>
</div>
</div>
<p></p><figcaption class="figure-caption">Figure&nbsp;3: Test that the site is running with a browser</figcaption><p></p>
</figure>
</div>
<div id="on-vms-ex2" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/on-machines-ex2.png" class="img-fluid figure-img" style="width:70.0%"></p>
<figcaption class="figure-caption">OpenNebula VMs</figcaption>
</figure>
</div>
<div id="fig-lbmethod" class="quarto-layout-panel">
<figure class="figure">
<div class="quarto-layout-row quarto-layout-valign-top">
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-byrequests" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/ab-test-1.ex2.png" class="img-fluid figure-img" data-ref-parent="fig-lbmethod"></p>
<figcaption class="figure-caption">(a) <code>lbmethod=byrequests</code> - 50 failed requests</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-bytraffic" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/ab-test-1.ex2.png" class="img-fluid figure-img" data-ref-parent="fig-lbmethod"></p>
<figcaption class="figure-caption">(b) <code>lbmethod=bytraffic</code> - 28 failed requests</figcaption>
</figure>
</div>
</div>
</div>
<p></p><figcaption class="figure-caption">Figure&nbsp;4: Test the command <code>ab -n 100 -c 10 84.88.58.82</code> with two balancing algorithms</figcaption><p></p>
</figure>
</div>
<div id="fig-balancer-manager" class="quarto-layout-panel">
<figure class="figure">
<div class="quarto-layout-row quarto-layout-valign-top">
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-balancer-manager-1" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/balancer-manager-1-ex2.png" class="img-fluid figure-img" data-ref-parent="fig-balancer-manager"></p>
<figcaption class="figure-caption">(a) Main <code>balancer-manager</code> page</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-balancer-manager-2" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/balancer-manager-2-ex2.png" class="img-fluid figure-img" data-ref-parent="fig-balancer-manager"></p>
<figcaption class="figure-caption">(b) Config for <code>worker1</code> in <code>balancer-manager</code></figcaption>
</figure>
</div>
</div>
</div>
<p></p><figcaption class="figure-caption">Figure&nbsp;5: <code>balance-manager</code> page</figcaption><p></p>
</figure>
</div>
<div id="fig-pages-ex2" class="quarto-layout-panel">
<figure class="figure">
<div class="quarto-layout-row quarto-layout-valign-top">
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-pages-1-ex2" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/website-test-1-ex2.png" class="img-fluid figure-img" data-ref-parent="fig-pages-ex2"></p>
<figcaption class="figure-caption">(a) Page from <code>worker1</code> accessed from <code>frontend</code></figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell quarto-layout-cell-subref" style="flex-basis: 50.0%;justify-content: center;">
<div id="fig-pages-2-ex2" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="./img/website-test-2-ex2.png" class="img-fluid figure-img" data-ref-parent="fig-pages-ex2"></p>
<figcaption class="figure-caption">(b) Page from <code>worker2</code> accessed from <code>frontend</code></figcaption>
</figure>
</div>
</div>
</div>
<p></p><figcaption class="figure-caption">Figure&nbsp;6: Pages served by each worker balanced from the <code>frontend</code></figcaption><p></p>
</figure>
</div>
<p>```</p>
</section>

</main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
  const toggleBodyColorMode = (bsSheetEl) => {
    const mode = bsSheetEl.getAttribute("data-mode");
    const bodyEl = window.document.querySelector("body");
    if (mode === "dark") {
      bodyEl.classList.add("quarto-dark");
      bodyEl.classList.remove("quarto-light");
    } else {
      bodyEl.classList.add("quarto-light");
      bodyEl.classList.remove("quarto-dark");
    }
  }
  const toggleBodyColorPrimary = () => {
    const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
    if (bsSheetEl) {
      toggleBodyColorMode(bsSheetEl);
    }
  }
  toggleBodyColorPrimary();  
  const icon = "";
  const anchorJS = new window.AnchorJS();
  anchorJS.options = {
    placement: 'right',
    icon: icon
  };
  anchorJS.add('.anchored');
  const isCodeAnnotation = (el) => {
    for (const clz of el.classList) {
      if (clz.startsWith('code-annotation-')) {                     
        return true;
      }
    }
    return false;
  }
  const clipboard = new window.ClipboardJS('.code-copy-button', {
    text: function(trigger) {
      const codeEl = trigger.previousElementSibling.cloneNode(true);
      for (const childEl of codeEl.children) {
        if (isCodeAnnotation(childEl)) {
          childEl.remove();
        }
      }
      return codeEl.innerText;
    }
  });
  clipboard.on('success', function(e) {
    // button target
    const button = e.trigger;
    // don't keep focus
    button.blur();
    // flash "checked"
    button.classList.add('code-copy-button-checked');
    var currentTitle = button.getAttribute("title");
    button.setAttribute("title", "Copied!");
    let tooltip;
    if (window.bootstrap) {
      button.setAttribute("data-bs-toggle", "tooltip");
      button.setAttribute("data-bs-placement", "left");
      button.setAttribute("data-bs-title", "Copied!");
      tooltip = new bootstrap.Tooltip(button, 
        { trigger: "manual", 
          customClass: "code-copy-button-tooltip",
          offset: [0, -8]});
      tooltip.show();    
    }
    setTimeout(function() {
      if (tooltip) {
        tooltip.hide();
        button.removeAttribute("data-bs-title");
        button.removeAttribute("data-bs-toggle");
        button.removeAttribute("data-bs-placement");
      }
      button.setAttribute("title", currentTitle);
      button.classList.remove('code-copy-button-checked');
    }, 1000);
    // clear code selection
    e.clearSelection();
  });
  function tippyHover(el, contentFn) {
    const config = {
      allowHTML: true,
      content: contentFn,
      maxWidth: 500,
      delay: 100,
      arrow: false,
      appendTo: function(el) {
          return el.parentElement;
      },
      interactive: true,
      interactiveBorder: 10,
      theme: 'quarto',
      placement: 'bottom-start'
    };
    window.tippy(el, config); 
  }
  const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
  for (var i=0; i<noterefs.length; i++) {
    const ref = noterefs[i];
    tippyHover(ref, function() {
      // use id or data attribute instead here
      let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
      try { href = new URL(href).hash; } catch {}
      const id = href.replace(/^#\/?/, "");
      const note = window.document.getElementById(id);
      return note.innerHTML;
    });
  }
      let selectedAnnoteEl;
      const selectorForAnnotation = ( cell, annotation) => {
        let cellAttr = 'data-code-cell="' + cell + '"';
        let lineAttr = 'data-code-annotation="' +  annotation + '"';
        const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
        return selector;
      }
      const selectCodeLines = (annoteEl) => {
        const doc = window.document;
        const targetCell = annoteEl.getAttribute("data-target-cell");
        const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
        const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
        const lines = annoteSpan.getAttribute("data-code-lines").split(",");
        const lineIds = lines.map((line) => {
          return targetCell + "-" + line;
        })
        let top = null;
        let height = null;
        let parent = null;
        if (lineIds.length > 0) {
            //compute the position of the single el (top and bottom and make a div)
            const el = window.document.getElementById(lineIds[0]);
            top = el.offsetTop;
            height = el.offsetHeight;
            parent = el.parentElement.parentElement;
          if (lineIds.length > 1) {
            const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
            const bottom = lastEl.offsetTop + lastEl.offsetHeight;
            height = bottom - top;
          }
          if (top !== null && height !== null && parent !== null) {
            // cook up a div (if necessary) and position it 
            let div = window.document.getElementById("code-annotation-line-highlight");
            if (div === null) {
              div = window.document.createElement("div");
              div.setAttribute("id", "code-annotation-line-highlight");
              div.style.position = 'absolute';
              parent.appendChild(div);
            }
            div.style.top = top - 2 + "px";
            div.style.height = height + 4 + "px";
            let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
            if (gutterDiv === null) {
              gutterDiv = window.document.createElement("div");
              gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
              gutterDiv.style.position = 'absolute';
              const codeCell = window.document.getElementById(targetCell);
              const gutter = codeCell.querySelector('.code-annotation-gutter');
              gutter.appendChild(gutterDiv);
            }
            gutterDiv.style.top = top - 2 + "px";
            gutterDiv.style.height = height + 4 + "px";
          }
          selectedAnnoteEl = annoteEl;
        }
      };
      const unselectCodeLines = () => {
        const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
        elementsIds.forEach((elId) => {
          const div = window.document.getElementById(elId);
          if (div) {
            div.remove();
          }
        });
        selectedAnnoteEl = undefined;
      };
      // Attach click handler to the DT
      const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
      for (const annoteDlNode of annoteDls) {
        annoteDlNode.addEventListener('click', (event) => {
          const clickedEl = event.target;
          if (clickedEl !== selectedAnnoteEl) {
            unselectCodeLines();
            const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
            if (activeEl) {
              activeEl.classList.remove('code-annotation-active');
            }
            selectCodeLines(clickedEl);
            clickedEl.classList.add('code-annotation-active');
          } else {
            // Unselect the line
            unselectCodeLines();
            clickedEl.classList.remove('code-annotation-active');
          }
        });
      }
  const findCites = (el) => {
    const parentEl = el.parentElement;
    if (parentEl) {
      const cites = parentEl.dataset.cites;
      if (cites) {
        return {
          el,
          cites: cites.split(' ')
        };
      } else {
        return findCites(el.parentElement)
      }
    } else {
      return undefined;
    }
  };
  var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
  for (var i=0; i<bibliorefs.length; i++) {
    const ref = bibliorefs[i];
    const citeInfo = findCites(ref);
    if (citeInfo) {
      tippyHover(citeInfo.el, function() {
        var popup = window.document.createElement('div');
        citeInfo.cites.forEach(function(cite) {
          var citeDiv = window.document.createElement('div');
          citeDiv.classList.add('hanging-indent');
          citeDiv.classList.add('csl-entry');
          var biblioDiv = window.document.getElementById('ref-' + cite);
          if (biblioDiv) {
            citeDiv.innerHTML = biblioDiv.innerHTML;
          }
          popup.appendChild(citeDiv);
        });
        return popup.innerHTML;
      });
    }
  }
});
</script>
</div> <!-- /content -->



</body></html>