CAA 2
Folders and files
Name | Name | 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">&&</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">>></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 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 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 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 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"><</span>Proxy <span class="ex">balancer://mycluster</span><span class="op">></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"><</span>/Proxy<span class="op">></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"><</span>Location <span class="ex">/balancer-manager</span><span class="op">></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"><</span>/Location<span class="op">></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"><</span>FrontendPublicIP<span class="op">></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 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://<FrontendPublicIP>/balancer-manager</code> is working (see <a href="#fig-balancer-manager">Figure 5</a>), and that both sites are served in the frontend (see <a href="#fig-pages-ex2">Figure 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">&&</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">></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"><</span>token<span class="op">></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 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 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 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 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 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 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>