<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Linux - Architect the cloud</title>
	<atom:link href="https://blog.slepcevic.net/category/linux/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.slepcevic.net</link>
	<description></description>
	<lastBuildDate>Wed, 29 Jan 2025 10:22:29 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>
	<item>
		<title>DeepSeek-R1 on Akamai Connected Cloud</title>
		<link>https://blog.slepcevic.net/deepseek-r1-on-akamai-connected-cloud-linode/</link>
					<comments>https://blog.slepcevic.net/deepseek-r1-on-akamai-connected-cloud-linode/#comments</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Tue, 28 Jan 2025 10:01:00 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">https://blog.slepcevic.net/?p=718</guid>

					<description><![CDATA[<p>Before we dive into installation and real usage, let&#8217;s talk about DeepSeek-R1 a bit and why it&#8217;s a big thing. The team behind DeepSeek-R1-Zero took a cool approach to advancing large language models by skipping supervised fine-tuning (SFT) entirely and...</p>
<p>The post <a href="https://blog.slepcevic.net/deepseek-r1-on-akamai-connected-cloud-linode/">DeepSeek-R1 on Akamai Connected Cloud</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="823" height="402" src="https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseeklogo-edited.png" alt="" class="wp-image-742" srcset="https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseeklogo-edited.png 823w, https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseeklogo-edited-300x147.png 300w, https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseeklogo-edited-768x375.png 768w" sizes="(max-width: 823px) 100vw, 823px" /></figure>



<p><strong>Before we dive into installation and real usage, let&#8217;s talk about DeepSeek-R1 a bit and why it&#8217;s a big thing</strong>. </p>



<p>The team behind DeepSeek-R1-Zero took a cool approach to advancing large language models by skipping supervised fine-tuning (SFT) entirely and jumping straight into reinforcement learning (RL). </p>



<p>This resulted in a model capable of self-verification, reflection, and generating intricate chain-of-thoughts (CoTs) to solve complex problems. What’s borderline groundbreaking here is that this is the first open research to show RL alone can incentivize reasoning in LLMs, without the need for SFT. Development pipeline for DeepSeek-R1 includes two RL stages to improve reasoning patterns and align with human preferences, along with two SFT stages to seed the model&#8217;s reasoning and non-reasoning capabilities. </p>



<p>They didn’t stop at advancing reasoning in large models—they also focused on making smaller models more powerful! By distilling the reasoning patterns of larger models into smaller ones, they achieved better performance than what RL alone could achieve on small models. </p>



<p>Using DeepSeek-R1’s reasoning data, they fine-tuned several dense models and demonstrated exceptional benchmark results. To further benefit the community, they’ve open-sourced distilled checkpoints ranging from 1.5B to 70B parameters, based on the Qwen2.5 and Llama3 series.</p>



<p><strong>What is distillation you may ask?</strong></p>



<p>In the context of AI, <strong>distillation</strong> (short for <em>knowledge distillation</em>) is a technique used to transfer knowledge from a larger, more complex model (called the <em>teacher</em>) to a smaller, simpler model (called the <em>student</em>). The goal is to make the smaller model perform as well as—or almost as well as—the larger model, while requiring significantly fewer resources (e.g., memory, computation).</p>



<h3 class="wp-block-heading">How Distillation Works:</h3>



<ol class="wp-block-list">
<li><strong>Training the Teacher Model:</strong><br>A large model is trained first. This model is usually highly expressive, capable of capturing complex patterns in the data, but it may be too computationally intensive for practical deployment.</li>



<li><strong>Soft Labels as Knowledge:</strong><br>Instead of just training the student model on the original dataset, the student learns from the <em>soft predictions</em> of the teacher model. These predictions include probability distributions over all possible outcomes (rather than binary correct/incorrect labels), which contain richer information about the relationships between classes.</li>



<li><strong>Student Model Training:</strong><br>The student model is trained to mimic the teacher’s behavior using a combination of:
<ul class="wp-block-list">
<li>The soft predictions from the teacher model (knowledge transfer).</li>



<li>The original ground-truth data.</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Why Distillation is Useful:</h3>



<ul class="wp-block-list">
<li><strong>Efficiency:</strong> Smaller models are faster, require less memory, and can run on devices with limited computational power (like mobile phones or edge devices).</li>



<li><strong>Scalability:</strong> By distilling large models into smaller ones, researchers and developers can deploy AI more broadly while maintaining strong performance.</li>



<li><strong>Accessibility:</strong> Distilled models often serve as the foundation for open-source projects, making advanced AI capabilities more accessible to the community.</li>
</ul>



<p>Ok, let&#8217;s get to the interesting part and deploy our model. We can break down the entire deployment in 4 easy steps.</p>



<p><strong>Step 1</strong> &#8211; Deploy a GPU VM in Linode. I&#8217;m gonna deploy the smallest GPU VM available &#8220;RTX4000 Ada x1 Small&#8221; which costs 350$ per month. </p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="554" src="https://blog.slepcevic.net/wp-content/uploads/2025/01/Screenshot-2025-01-29-100730-1024x554.png" alt="" class="wp-image-719" srcset="https://blog.slepcevic.net/wp-content/uploads/2025/01/Screenshot-2025-01-29-100730-1024x554.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2025/01/Screenshot-2025-01-29-100730-300x162.png 300w, https://blog.slepcevic.net/wp-content/uploads/2025/01/Screenshot-2025-01-29-100730-768x415.png 768w, https://blog.slepcevic.net/wp-content/uploads/2025/01/Screenshot-2025-01-29-100730.png 1413w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Step 2</strong> &#8211; Connect using SSH to your instance and install Nvidia drivers</p>



<p>Since I&#8217;m using Debian 12 as my OS, installing Nvidia drivers was quite easy following official instructions &#8211; <a href="https://wiki.debian.org/NvidiaGraphicsDrivers" target="_blank" rel="noopener" title="">https://wiki.debian.org/NvidiaGraphicsDrivers</a></p>



<p>After the driver has been install, I suggest you also install &#8220;nvtop&#8221; using: </p>



<pre class="wp-block-code"><code>apt install nvtop</code></pre>



<p></p>



<p><strong>nvtop </strong>is a cool utility which can monitor the usage of your GPU. Think of it like a &#8220;top&#8221; command, but for GPU&#8217;s. </p>



<p><strong>Step 3</strong> &#8211; Install Ollama</p>



<p>Installing Ollama is extremely simple, all you need to do it run a single command. </p>



<pre class="wp-block-code"><code>curl -fsSL https://ollama.com/install.sh | sh</code></pre>



<p></p>



<p><strong>Step 4</strong> &#8211; Download and run the DeepSeek-R1 model into Ollama. Since the GPU I will be using has 20 GB of VRAM, we can fit a 14B model without any issues. </p>



<p>&#8211;verbose flag tells Ollama to display performance metrics after the generation has been completed. </p>



<pre class="wp-block-code"><code>ollama run deepseek-r1:14b --verbose
</code></pre>



<p></p>



<p>Let&#8217;s ask a simple question and see how it performs: <strong>What is distilling in the context of AI?</strong></p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>&lt;think&gt;</strong></p>



<p>Hmm, distillation… I think it&#8217;s related to machine learning, specifically in training<br>models. Maybe it&#8217;s about transferring knowledge from one model to another? Let me recall.<br>Oh right, model distillation is the process where you take a complex, large model and<br>create a smaller, more efficient version that retains the same performance.</p>



<p>Wait, there are different types of distillation too. I should mention those. There&#8217;s<br>knowledge distillation where you transfer knowledge from a teacher model to a student<br>model. Then there&#8217;s parameter-efficient methods like fine-tuning or adapter-based<br>approaches. Also, pruning and quantization techniques come under distilling in terms of<br>optimizing models.</p>



<p>I need to make sure the explanation is clear but not too technical. The user might be<br>someone new to AI or looking to understand optimization techniques. They probably want a<br>practical understanding without getting bogged down by jargon.</p>



<p>Maybe I should start with the general idea, then break it down into types, and explain<br>each briefly. Also, highlighting why it&#8217;s important—like efficiency, scalability,<br>deployment on devices—would be helpful for them to grasp its value.</p>



<p>I should keep the response structured but conversational, avoiding any markdown. Just<br>plain, easy-to-understand English. Let me put that together.<br><strong>&lt;/think&gt;</strong></p>



<p>In the context of AI and machine learning, <strong>distilling</strong> refers to a technique where<br>knowledge or information from one model is transferred to another, often simpler or<br>smaller model. This process aims to create a more efficient version of the original model<br>while preserving its performance.</p>



<h3 class="wp-block-heading">Key Ideas:</h3>



<ol class="wp-block-list">
<li><strong>Model Distillation</strong>:</li>
</ol>



<ul class="wp-block-list">
<li>It involves training a &#8220;student&#8221; model to mimic the behavior or decisions of a<br>larger, more complex &#8220;teacher&#8221; model.</li>



<li>The teacher model is typically pre-trained on a large dataset and has high accuracy<br>but may be computationally expensive or difficult to deploy.</li>
</ul>



<ol class="wp-block-list">
<li><strong>Types of Distillation</strong>:</li>
</ol>



<ul class="wp-block-list">
<li><strong>Knowledge Distillation</strong>: The teacher model&#8217;s predictions (soft labels) are used to<br>train the student model, which can lead to better generalization compared to using only<br>hard labels.</li>



<li><strong>Parameter-Efficient Methods</strong>: Techniques like fine-tuning, adapter-based<br>approaches, or prompt tuning allow the transfer of knowledge without copying all<br>parameters from the teacher model.</li>



<li><strong>Pruning and Quantization</strong>: These are techniques used to reduce the size of a model<br>by removing unnecessary weights (pruning) or reducing the precision of the weights<br>(quantization).</li>
</ul>



<ol class="wp-block-list">
<li><strong>Applications</strong>:</li>
</ol>



<ul class="wp-block-list">
<li>Distillation is widely used to deploy AI models on edge devices where computational<br>resources are limited.</li>



<li>It also helps in scaling down large models for faster inference while maintaining<br>performance.</li>
</ul>



<p>In summary, distilling in AI is about making complex models more efficient and accessible<br>by transferring their knowledge to simpler or smaller models.</p>



<p></p>
</blockquote>



<pre class="wp-block-code"><code>total duration: 19.004002094s
load duration: 12.267119ms
prompt eval count: 105 token(s)
prompt eval duration: 48ms
prompt eval rate: 2187.50 tokens/s
eval count: 615 token(s)
eval duration: 18.938s
<strong>eval rate: 32.47 tokens/s</strong></code></pre>



<p></p>



<p>One major difference between DeepSeek-R1 and majority of other generative AI models is that DeepSeek will show you the &#8220;train of thought&#8221; it used to get to the answer, not just the answer itself. </p>



<p></p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="364" src="https://blog.slepcevic.net/wp-content/uploads/2025/01/ollama3-1024x364.png" alt="" class="wp-image-720" srcset="https://blog.slepcevic.net/wp-content/uploads/2025/01/ollama3-1024x364.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2025/01/ollama3-300x107.png 300w, https://blog.slepcevic.net/wp-content/uploads/2025/01/ollama3-768x273.png 768w, https://blog.slepcevic.net/wp-content/uploads/2025/01/ollama3-1536x546.png 1536w, https://blog.slepcevic.net/wp-content/uploads/2025/01/ollama3.png 1570w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Once we have the model running locally, we can turn it into our own personal AI assistant by using <a href="https://github.com/open-webui/open-webui" target="_blank" rel="noopener" title="Open-WebUI">Open-WebUI</a> or turn it into your own coding assistant using <a href="https://github.com/stackblitz-labs/bolt.diy" target="_blank" rel="noopener" title="Bolt.diy">Bolt.diy</a>. </p>



<p>Ollama also has it&#8217;s on <a href="https://github.com/ollama/ollama/blob/main/docs/api.md" target="_blank" rel="noopener" title="API">API</a> which you can use to embed the model into your own applications.</p>



<p><strong>Possibilities are endless!</strong></p>



<p>BTW, we can even run a <strong>32B parameter model,</strong> but the performance drops to 10 tokens per second and spills a bit into the RAM and CPU, but nothing drastic. Model is still fully usable and comparable to ChatGPT on a busy day.  </p>



<p>Results you can see on the image are based on the request to build me &#8220;Space Invaders&#8221; game in HTML. </p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="792" height="394" src="https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseek32b.png" alt="" class="wp-image-734" style="width:840px;height:auto" srcset="https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseek32b.png 792w, https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseek32b-300x149.png 300w, https://blog.slepcevic.net/wp-content/uploads/2025/01/deepseek32b-768x382.png 768w" sizes="auto, (max-width: 792px) 100vw, 792px" /></figure>



<p>Until next time where we will take a look into bolt.diy and deploy our own coding assistant!</p>



<p>Alex!</p>



<p></p><p>The post <a href="https://blog.slepcevic.net/deepseek-r1-on-akamai-connected-cloud-linode/">DeepSeek-R1 on Akamai Connected Cloud</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/deepseek-r1-on-akamai-connected-cloud-linode/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Get your own own Github runner deployed and configured on Linode in less than 5 minutes.</title>
		<link>https://blog.slepcevic.net/get-your-own-own-github-runner-deployed-and-configured-on-linode-in-less-than-5-minutes/</link>
					<comments>https://blog.slepcevic.net/get-your-own-own-github-runner-deployed-and-configured-on-linode-in-less-than-5-minutes/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Wed, 23 Oct 2024 23:19:20 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[GitHub runner]]></category>
		<category><![CDATA[Linux]]></category>
		<guid isPermaLink="false">https://blog.slepcevic.net/?p=685</guid>

					<description><![CDATA[<p>Why would you run your own runner anyways? GitHub Actions (along with Azure DevOps) has emerged as a powerful managed tool that allows developers to automate workflows directly within their GitHub repositories. While GitHub provides hosted runners to execute these...</p>
<p>The post <a href="https://blog.slepcevic.net/get-your-own-own-github-runner-deployed-and-configured-on-linode-in-less-than-5-minutes/">Get your own own Github runner deployed and configured on Linode in less than 5 minutes.</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><strong>Why would you run your own runner anyways?</strong></p>



<p>GitHub Actions (along with Azure DevOps) has emerged as a powerful managed tool that allows developers to automate workflows directly within their GitHub repositories. While GitHub provides hosted runners to execute these workflows, running your own GitHub runner can offer several advantages. </p>



<p><strong>1. Money talks</strong></p>



<p>One of the primary benefits of running your own GitHub runner is cost efficiency. GitHub Actions provides a certain number of free minutes for public and private repositories, but once you exceed these limits, costs can add up quickly, especially if your execution takes a while <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p><strong>2</strong>. <strong>Customization and Control</strong></p>



<p>When you run your own GitHub runner, you gain full control over the environment in which your workflows execute. This means you can customize the runner&#8217;s operating system, software, and dependencies to match your project’s specific needs. It doesn&#8217;t matter anymore if you need a particular version of a programming language, specialized libraries, or specific system configurations, your self-hosted runner can be tailored to your requirements.</p>



<p><strong>3</strong>. <strong>Performance and Speed</strong></p>



<p>Self-hosted runners can significantly enhance the performance of your CI/CD pipelines. Since these runners are dedicated to your projects, you can optimize them for speed and efficiency. You can run builds on beefy machines, use faster storage, or even set up parallel execution across multiple runners to speed up your workflows. This is especially beneficial for larger projects or teams with multiple repositories or a bunch of members working in parallel. </p>



<p><strong>4. Security and Compliance</strong></p>



<p>For organizations handling sensitive data or operating in regulated industries, security is number one. Running your own GitHub runner allows you to maintain control over your CI/CD environment. You can implement your own security measures, restrict network access, and ensure that sensitive information does not leave your secured infrastructure. Additionally, you can regularly update and audit your runner to comply with internal policies or external regulations.</p>



<p><strong>5. Reduced Queue Times</strong></p>



<p>Using GitHub&#8217;s hosted runners means you may encounter queue times, especially during peak usage periods. By setting up your own runners, you can mitigate these delays, ensuring that your workflows kick off as soon as possible. </p>



<p><strong>How do I get it running? </strong></p>



<p><strong>Step 1</strong> &#8211; Clone the repository using the following command. </p>



<pre class="wp-block-code"><code>git clone https://github.com/slepix/GitHubRunner-Linode.git</code></pre>



<p></p>



<h5 class="wp-block-heading">You will need to prepare 5 things; it&#8217;s not hard, I promise. </h5>



<ol class="wp-block-list">
<li><strong>Linode API token</strong> with permission to deploy virtual machines &#8211; <a href="https://techdocs.akamai.com/cloud-computing/docs/manage-personal-access-tokens" target="_blank" rel="noopener" title="">more info</a></li>



<li><strong>GitHub PAT</strong> limited only to the repository you want to connect &#8211;<a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens" target="_blank" rel="noopener" title=""> more details</a></li>



<li><strong>GitHub repository</strong> name you want to connect your runner to. </li>



<li><strong>GitHub username</strong> which owns the repository. </li>



<li><strong>Root password</strong> for the runner VM &#8211; can be anything, as long as it&#8217;s long and complex. </li>
</ol>



<p><strong>Step 2</strong> &#8211; Fill in the details in <strong>linoderunner.tfvars</strong> file; it should look something like this. </p>



<p>*These are random values, so make sure to replace them with your own. </p>



<pre class="wp-block-code"><code>linode_api_token = "eee44387b0030bd6bb051452bg65gz56z465fba5d77c5a238ea8e12f"
github_pat = "github_pat_1HG534e67d3K52IUSL_D2vM1pzjDGjX5sCiUEXWD6TRKDut4jnJty"
root_password = "Rand0mSecurePassword.123!" # Root password for your VM
github_repo = "myawesomeapp" # Your Github repo name
github_username = "slepix" # Your GitHub username</code></pre>



<p><strong>Step 3</strong> &#8211; run the following command:</p>



<pre class="wp-block-code"><code>terraform apply --var-file="linoderunner.tfvars"</code></pre>



<p>Entire codebase is available at <a href="https://github.com/slepix/GithubRunner-Linode" target="_blank" rel="noopener" title="">https://github.com/slepix/GithubRunner-Linode</a></p>



<p>Ok, let&#8217;s take a look at some code. Once again, we&#8217;ll go with Terraform and cloud-init to deploy and configure our server. Ideally you would use some configuration management tool like Puppet, Ansible, Chef or similar, but for this use case, we can keep it simple. </p>



<p>Using cloud-init, we create a new user called &#8220;<strong>gitrunner</strong>&#8221; which will be used to run the agent, update all the packes, install jq (needed by the agent configuration script) and kick off the installation of the runner as a service. </p>



<p><strong>compute.tf file</strong> &#8211; this is where you can adjust the region, OS and instance type you want to run. </p>



<pre class="wp-block-code"><code>resource "linode_instance" "github_runner" {
  image     = "linode/ubuntu22.04"
  region    = "nl-ams"
  type      = "g6-nanode-1"
  label     = "github-runner"
  root_pass = var.root_password  # Set the root password

  metadata {
    user_data = base64encode(templatefile("./linode.yaml.tpl", {
      githubpat = var.github_pat
      githubuser = var.github_username
      githubrepo = var.github_repo
    }))
  }
}</code></pre>



<p><strong>linode.yaml.tpl file</strong></p>



<pre class="wp-block-code"><code>#cloud-config
package_update: true
packages:
  - jq

users:
  - name: gitrunner
    shell: /bin/bash
    groups:
      - sudo
    sudo:
      - ALL=(ALL) NOPASSWD:ALL

runcmd:
  - export RUNNER_CFG_PAT=${githubpat}
  - su gitrunner -c "cd /home/gitrunner &amp;&amp; curl -s https://raw.githubusercontent.com/actions/runner/main/scripts/create-latest-svc.sh | bash -s ${githubuser}/${githubrepo}" 
</code></pre>



<p>If all went good, you should see the new GitHub runner appear in your runner overview in a few mins. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="316" src="https://blog.slepcevic.net/wp-content/uploads/2024/10/runner-1024x316.png" alt="" class="wp-image-686" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/10/runner-1024x316.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2024/10/runner-300x92.png 300w, https://blog.slepcevic.net/wp-content/uploads/2024/10/runner-768x237.png 768w, https://blog.slepcevic.net/wp-content/uploads/2024/10/runner.png 1152w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Happy building and deploying!</p>



<p>Alex!</p><p>The post <a href="https://blog.slepcevic.net/get-your-own-own-github-runner-deployed-and-configured-on-linode-in-less-than-5-minutes/">Get your own own Github runner deployed and configured on Linode in less than 5 minutes.</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/get-your-own-own-github-runner-deployed-and-configured-on-linode-in-less-than-5-minutes/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Powershell module for Linode &#8211; Akamai Connected Cloud</title>
		<link>https://blog.slepcevic.net/powershell-module-for-linode-akamai-connected-cloud/</link>
					<comments>https://blog.slepcevic.net/powershell-module-for-linode-akamai-connected-cloud/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Sun, 30 Jun 2024 13:09:53 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Linode]]></category>
		<category><![CDATA[Linode PowerShell Module]]></category>
		<category><![CDATA[Powershell module]]></category>
		<guid isPermaLink="false">https://blog.slepcevic.net/?p=487</guid>

					<description><![CDATA[<p>Even though I consider myself as being &#8220;platform-agnostic&#8221;, I originally come from a Microsoft side of the industry and because of that I had a lot of exposure to PowerShell. After a relatively steep learning curve, I realized that PowerShell...</p>
<p>The post <a href="https://blog.slepcevic.net/powershell-module-for-linode-akamai-connected-cloud/">Powershell module for Linode – Akamai Connected Cloud</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Even though I consider myself as being &#8220;platform-agnostic&#8221;, I originally come from a Microsoft side of the industry and because of that I had a lot of exposure to PowerShell. </p>



<p>After a relatively steep learning curve, I realized that PowerShell is cool and VERY powerful for some use cases. </p>



<p></p>



<p>Well, as a small side project, I started working on a <a href="https://github.com/slepix/LinodePowerShell" target="_blank" rel="noopener" title="">Powershell module</a> for Akamai Connected Cloud (Linode) platform.</p>



<p><strong>Why? Why not!? </strong></p>



<p>Linode is already known as being <a href="https://www.linode.com/developers/" target="_blank" rel="noopener" title="">VERY developer friendly</a>, why not make it even more friendlier <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>General idea was to generate a module which will directly talk to the Linode API and eventually expose all platform features via some commandlet. </p>



<p>Besides that, I also wanted to implement some quality of life features which current Linode CLI doesn&#8217;t have.</p>



<h5 class="wp-block-heading">Using the label/name of the resource in your commands.</h5>



<p>With the current <a href="https://www.linode.com/docs/products/tools/cli/get-started/" target="_blank" rel="noopener" title="">linode-cli</a>, you need to use the resource ID in all commands which is a bit annoying for some use cases <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>With this module, you can use the resource label/name in your commands, and in the background the module will convert the label provided to a resource ID and use that to talk to the API. </p>



<h5 class="wp-block-heading">Support for multiple Linode accounts and account switching.</h5>



<p>I also implemented the possibility to have and switch between multiple different Linode &#8220;profiles&#8221;. </p>



<p>You can have a profile for your development Linode account, a profile for your test Linode account and switch between them using a single command. </p>



<h5 class="wp-block-heading">Generate a random password when launching an instance</h5>



<p>When you deploy instances with the linode-cli, you need to provide a password for the instance. </p>



<p>Since humans are lazy, we most probably end up using the same password over and over again. This feature will make sure that you always get a secure password generated for your Linode. Of course, you are still free to provide your own password if you like. </p>



<h6 class="wp-block-heading"><strong>Check out the examples below to see how all of these things work. </strong></h6>



<p></p>



<h4 class="wp-block-heading"><strong>How to start? It&#8217;s really easy! You will be up and running in less than 2 minutes!</strong></h4>



<h4 class="wp-block-heading">Installation</h4>



<p>To install the Linode PowerShell module, you need to clone the repository, position yourself into the module folder and import the module:</p>



<pre class="wp-block-code"><code>git clone https://github.com/slepix/LinodePowerShell.git
cd LinodePowerShell</code></pre>



<p></p>



<h4 class="wp-block-heading">Usage</h4>



<p>Before you can use the module, you need to import it using the following command:</p>



<pre class="wp-block-code"><code>Import-Module -Name .\LinodePSModule.psd1</code></pre>



<p>After the module has been imported, you need to configure it and add your Linode account.</p>



<h4 class="wp-block-heading">Configuration</h4>



<p>Configuration is really simple, all you need to do is run&nbsp;<strong>&#8216;Connect-LinodeAccount&#8217;</strong>&nbsp;command and follow the configuration wizard.</p>



<pre class="wp-block-code"><code>Connect-LinodeAccount</code></pre>



<p></p>



<p><strong>You can run </strong>&#8220;Connect-LinodeAccount&#8221; <strong>command for each Linode account you want to add.</strong></p>



<pre class="wp-block-preformatted">IMPORTANT!!!<br>When creating a new profile, you will be asked if you want to encrypt your Linode token or not. If you decide to encrypt the token, you won't be able to manually edit the profile file and edit the token. <br><br>It is recommended that you use encrypted profile option and recreate a profile if you need to change the token.<br></pre>



<p>User configuration is stored in &#8220;<strong>$HOME\.LinodePSModule\$name-profile.json</strong>&#8220;</p>



<p>Check in the examples below how you can switch between different Linode accounts.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><em><strong>NOTE:</strong></em><br><strong>You will need Linode API token with the READ/WRITE permissions for all resources in order to get the full functionality of this module.<br>However, you are free to limit the scope of the API token to suit your security and usage requirements</strong>.</p>
</blockquote>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="350" src="https://blog.slepcevic.net/wp-content/uploads/2024/06/blogpsmodule-1024x350.png" alt="" class="wp-image-609" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/06/blogpsmodule-1024x350.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2024/06/blogpsmodule-300x103.png 300w, https://blog.slepcevic.net/wp-content/uploads/2024/06/blogpsmodule-768x262.png 768w, https://blog.slepcevic.net/wp-content/uploads/2024/06/blogpsmodule.png 1191w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p></p>



<h4 class="wp-block-heading">Available commands</h4>



<p><a href="https://github.com/slepix/LinodePowerShell#commands"></a></p>



<p>List of currently available commands can be viewed by running this command</p>



<pre class="wp-block-code"><code>(Get-Module LinodePSModule).ExportedCommands</code></pre>



<p></p>



<h4 class="wp-block-heading">Example commands</h4>



<p><a href="https://github.com/slepix/LinodePowerShell#example-commands"></a></p>



<p><strong>List all currently configured profiles</strong></p>



<pre class="wp-block-code"><code>PS C:\&gt; Get-LinodeProviderProfiles # returns a list of all configured profiles
development
test</code></pre>



<p></p>



<p><strong>Switch to a profile named &#8220;test&#8221;</strong></p>



<pre class="wp-block-code"><code>PS C:\&gt; Set-LinodeProviderProfile -profile test
Profile test loaded</code></pre>



<p></p>



<p><strong>Get a list of all regions, but only return label, id and status of each region</strong></p>



<pre class="wp-block-code"><code>PS C:\&gt; Get-LinodeRegions | Select label, id, status

label           id           status
-----           --           ------
Mumbai, IN      ap-west      ok
Toronto, CA     ca-central   ok
Sydney, AU      ap-southeast ok
Washington, DC  us-iad       ok
Chicago, IL     us-ord       ok
Paris, FR       fr-par       ok
Seattle, WA     us-sea       ok
Sao Paulo, BR   br-gru       ok
Amsterdam, NL   nl-ams       ok
Stockholm, SE   se-sto       ok
Madrid, ES      es-mad       ok
Chennai, IN     in-maa       ok
Osaka, JP       jp-osa       ok
Milan, IT       it-mil       ok
Miami, FL       us-mia       ok
Jakarta, ID     id-cgk       ok
Los Angeles, CA us-lax       ok
Dallas, TX      us-central   ok
Fremont, CA     us-west      ok
Atlanta, GA     us-southeast ok
Newark, NJ      us-east      ok
London, UK      eu-west      ok
Singapore, SG   ap-south     ok
Frankfurt, DE   eu-central   ok
Tokyo, JP       ap-northeast ok</code></pre>



<p></p>



<p></p>



<p><strong>Returns all properties of a single region</strong></p>



<pre class="wp-block-code"><code>PS C:\&gt; Get-LinodeRegion -region nl-ams # list only nl-ams region

id                     : nl-ams
label                  : Amsterdam, NL
country                : nl
capabilities           : {Linodes, Backups, NodeBalancers, Block Storage...}
status                 : ok
resolvers              : @{ipv4=172.233.33.36, 172.233.33.38, 172.233.33.35,     172.233.33.39, 172.233.33.34, 172.233.33.33, 172.233.33.31, 172.233.33.30, 172.233.33.37, 172.233.33.32;
                         ipv6=2600:3c0e::f03c:93ff:fe9d:2d10, 2600:3c0e::f03c:93ff:fe9d:2d89, 2600:3c0e::f03c:93ff:fe9d:2d79, 2600:3c0e::f03c:93ff:fe9d:2d96, 2600:3c0e::f03c:93ff:fe9d:2da5,     
                         2600:3c0e::f03c:93ff:fe9d:2d34, 2600:3c0e::f03c:93ff:fe9d:2d68, 2600:3c0e::f03c:93ff:fe9d:2d17, 2600:3c0e::f03c:93ff:fe9d:2d45, 2600:3c0e::f03c:93ff:fe9d:2d5c}
placement_group_limits : @{maximum_pgs_per_customer=100; maximum_linodes_per_pg=5}
site_type              : core</code></pre>



<p></p>



<p>Create a new Linode named &#8220;<strong>myInstance</strong>&#8221; with the instance type of &#8220;<strong>g6-nanode-1</strong>&#8221; in <strong>nl-ams</strong> region and a <strong>randomly generated password</strong> <strong>25 characters long</strong> running <strong>Debian 11</strong></p>



<pre class="wp-block-code"><code>PS C:\&gt; New-LinodeInstance -label myInstance -region nl-ams -type g6-nanode-1 -image linode/debian11 -generatepassword -passwordlength 25


id               : 60827598
label            : myInstance
group            :
status           : provisioning
created          : 2024-06-30T01:23:46
updated          : 2024-06-30T01:23:46
type             : g6-nanode-1
ipv4             : {172.233.40.46}
ipv6             : 2600:3c0e::f03c:94ff:fe85:29cf/128
image            : linode/debian11
region           : nl-ams
specs            : @{disk=25600; memory=1024; vcpus=1; gpus=0; transfer=1000}
alerts           : @{cpu=90; network_in=10; network_out=10; transfer_quota=80; io=10000}
backups          : @{enabled=False; available=False; schedule=; last_successful=}
hypervisor       : kvm
watchdog_enabled : True
tags             : {}
host_uuid        : 5f337dda11805445fc391c91e6dcbf45c2a38a21
has_user_data    : False
placement_group  :
lke_cluster_id   :
root_password    : eJbd\OQC9ypSagfvTSG@XREV4</code></pre>



<p></p>



<p><strong>Delete a Linode instance</strong></p>



<p><strong>All destructive commands</strong> will force you to use &#8220;-confirm&#8221; flag in order to actually delete a resource.</p>



<pre class="wp-block-code"><code>PS C:\&gt; Remove-LinodeInstance -label myInstance  
Please use the -confirm flag in order to delete an instance</code></pre>



<p></p>



<pre class="wp-block-code"><code>PS C:\&gt; Remove-LinodeInstance -label myInstance -confirm
Instance 60827598 deleted</code></pre>



<p></p>



<h5 class="wp-block-heading">Every other command</h5>



<p>Even though each commandlet will ask you for parameters, you can also use&nbsp;<em><strong>&#8216;Get-Help&#8217;</strong></em>&nbsp;commandlet in order to find out which parameters each command requires.</p>



<p><strong>Example for &#8220;New-LinodeVPC&#8221; command:</strong></p>



<pre class="wp-block-code"><code>PS /&gt; Get-Help New-LinodeVPC

NAME
    New-LinodeVPC

SYNTAX
    New-LinodeVPC &#91;&#91;-description] &lt;string&gt;] &#91;&#91;-apiVersion] &lt;string&gt;] &#91;&#91;-label] &lt;string&gt;] &#91;&#91;-token] &lt;string&gt;] &#91;&#91;-region] &lt;string&gt;] &#91;&#91;-subnetlabel] &lt;string&gt;] &#91;&#91;-iprange] &lt;string&gt;] &#91;&lt;CommonParameters&gt;]

ALIASES
    None

REMARKS
    None</code></pre>



<p></p>



<h4 class="wp-block-heading"></h4>



<p></p>



<h4 class="wp-block-heading">Cool stuff and other quality of life improvements</h4>



<p>Compared to Linode&#8217;s existing CLI, this module will allow you to specify a label for most of the resources you&#8217;re working with. In the background the module will convert the label to the ID of the resource for you.</p>



<p>Example of retrieving an instance details using&nbsp;<a href="https://www.linode.com/docs/products/tools/cli/guides/install/">linode-cli</a>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="415" src="https://blog.slepcevic.net/wp-content/uploads/2024/06/linodecli-1024x415.png" alt="" class="wp-image-517" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/06/linodecli-1024x415.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2024/06/linodecli-300x121.png 300w, https://blog.slepcevic.net/wp-content/uploads/2024/06/linodecli-768x311.png 768w, https://blog.slepcevic.net/wp-content/uploads/2024/06/linodecli.png 1089w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Example retrieving an instance details using Linode Powershell module:</strong></p>



<pre class="wp-block-code"><code>PS C:\&gt; Get-Linodeinstance -label blog.dummyserver.net

id               : 12374123
label            : blog.dummyserver.net
group            :
status           : running
created          : 2024-02-29T17:53:49
updated          : 2024-06-29T00:35:47
type             : g6-standard-2
ipv4             : {172.123.123.123}
ipv6             : 2600:4c0e::f04c:95ff:fe48:cda4/128
image            : linode/ubuntu22.04
region           : nl-ams
specs            : @{disk=81920; memory=4096; vcpus=2; gpus=0; transfer=4000}
alerts           : @{cpu=180; network_in=10; network_out=10; transfer_quota=80; io=10000}
backups          : @{enabled=True; available=True; schedule=; last_successful=2024-06-29T00:29:24}
hypervisor       : kvm
watchdog_enabled : True
tags             : {prod}
host_uuid        : 123f8e495e9d51c53df4fa074e5844bce944a068
has_user_data    : True
placement_group  :
lke_cluster_id   :</code></pre>



<p></p>



<h4 class="wp-block-heading">Development status as of 30.06.2024</h4>



<figure class="wp-block-table alignwide"><table><tbody><tr><td>Percent complete</td><td><strong>51.35%</strong></td></tr><tr><td>Total API commands:</td><td>368</td></tr><tr><td>Implemented Powershell commands</td><td>189</td></tr></tbody></table></figure>



<p>Live status: <a href="https://docs.google.com/spreadsheets/d/1UCzCSL3fRUB6cJKZJBUFEq-hPzaxGcS7B37nP12Ee3I/edit?gid=1065465499#gid=1065465499" target="_blank" rel="noopener" title="">https://docs.google.com/spreadsheets/d/1UCzCSL3fRUB6cJKZJBUFEq-hPzaxGcS7B37nP12Ee3I/edit?gid=1065465499#gid=1065465499</a></p>



<p>Development is focused on providing the <strong>most important features from the start</strong>, so that&#8217;s the reason you will see a lot of less important functionalities being implemented halfway or &#8220;almost there&#8221;.</p>



<p>This is a very active project and my expectation is that in the next few weeks there will be full coverage.</p>



<p>Status of implementation is as follows:</p>



<figure class="wp-block-table"><table><thead><tr><th>Area</th><th>Status</th><th>Notes</th></tr></thead><tbody><tr><td><strong>Account</strong></td><td><strong>Done</strong></td><td>All functionalities besides billing available.</td></tr><tr><td><strong>Beta programs</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available</strong></td></tr><tr><td><strong>Account availability</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available</strong></td></tr><tr><td><strong>Child accounts</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Payments</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Entity transfers</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Events</strong></td><td>WIP</td><td>Everything besides &#8220;Mark as read/seen&#8221; has been implemented</td></tr><tr><td><strong>Invoices</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available</strong></td></tr><tr><td><strong>Logins</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available</strong></td></tr><tr><td><strong>Maintenances</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available</strong></td></tr><tr><td><strong>Notifications</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available</strong></td></tr><tr><td><strong>Oauth Clients</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Client thumbnails</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Payment methods</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Promo credits</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Service transfers</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Account settings</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Settings</strong></td><td>Not started</td><td>None</td></tr><tr><td><strong>Account transfer</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available.</strong></td></tr><tr><td><strong>Users</strong></td><td><strong>Done</strong></td><td>Everything besides &#8220;Update user&#8217;s grant&#8221; command is implemented.</td></tr><tr><td><strong>Beta programs</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available.</strong></td></tr><tr><td><strong>Databases</strong></td><td>WIP</td><td>MySQL 95% done, PostgreSQL 0%.</td></tr><tr><td><strong>Domains</strong></td><td>WIP</td><td>All GET commands done, 80% of write commands done.</td></tr><tr><td><strong>Images</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available.</strong></td></tr><tr><td><strong>Instances</strong></td><td>WIP</td><td>60% done. Most important features like VM management are already available</td></tr><tr><td><strong>StackScripts</strong></td><td>WIP</td><td>80% done. All &#8220;GET&#8221; commands available</td></tr><tr><td><strong>LKE</strong></td><td>WIP</td><td>95% done. All &#8220;GET&#8221; commands available</td></tr><tr><td><strong>Longview</strong></td><td>WIP</td><td>0% done</td></tr><tr><td><strong>Managed</strong></td><td>WIP</td><td>0% done</td></tr><tr><td><strong>Networking</strong></td><td>WIP</td><td>80% done. All &#8220;GET&#8221; commands available</td></tr><tr><td><strong>NodeBalancers</strong></td><td>WIP</td><td>80% done. All &#8220;GET&#8221; commands available</td></tr><tr><td><strong>Object storage</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available.</strong></td></tr><tr><td><strong>Placement groups</strong></td><td>WIP</td><td>0% done</td></tr><tr><td><strong>Profile</strong></td><td>WIP</td><td>0% done</td></tr><tr><td><strong>Regions</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available.</strong></td></tr><tr><td><strong>Support</strong></td><td>WIP</td><td>0% done</td></tr><tr><td><strong>Tags</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available.</strong></td></tr><tr><td><strong>Volumes</strong></td><td>WIP</td><td>50% done</td></tr><tr><td><strong>VPC</strong></td><td><strong>Done</strong></td><td><strong>All functionalities available.</strong></td></tr></tbody></table></figure>



<h4 class="wp-block-heading">Roadmap</h4>



<p>Since this is a &#8220;weekend&#8221; project, no dates will be listed here <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p> Project is under very active development and I&#8217;m expecting to finish the first stage in the next few weeks</p>



<p></p>



<ul class="wp-block-list">
<li><strong>Stage 1 &lt; -WE ARE HERE (30.06.2024)</strong>
<ul class="wp-block-list">
<li>Full functionality coverage &#8211; 45% done</li>
</ul>
</li>



<li>Stage 2
<ul class="wp-block-list">
<li>Write Pester tests for all functionalities</li>
</ul>
</li>



<li>Stage 3
<ul class="wp-block-list">
<li>Build test and release pipelines</li>
</ul>
</li>



<li>Stage 4
<ul class="wp-block-list">
<li>Get a signing certificate &amp; publish to NuGet gallery if project gets enough traction</li>
</ul>
</li>
</ul>



<h4 class="wp-block-heading">Contributing</h4>



<p>To report a bug or request a feature in the module, please open a&nbsp;<a href="https://github.com/slepix/LinodePowerShell/issues">GitHub Issue</a>. Will be happy to check it out &lt;3</p>



<p>Have fun with it, please provide feedback (especially around naming commandlets) and until next time <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Alex!</p><p>The post <a href="https://blog.slepcevic.net/powershell-module-for-linode-akamai-connected-cloud/">Powershell module for Linode – Akamai Connected Cloud</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/powershell-module-for-linode-akamai-connected-cloud/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Easy way to deploy Linode instances across all (core) regions using Terraform</title>
		<link>https://blog.slepcevic.net/easy-way-to-deploy-linode-instances-across-all-core-regions-using-terraform/</link>
					<comments>https://blog.slepcevic.net/easy-way-to-deploy-linode-instances-across-all-core-regions-using-terraform/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Mon, 03 Jun 2024 22:57:35 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Linode regions]]></category>
		<guid isPermaLink="false">https://blog.slepcevic.net/?p=426</guid>

					<description><![CDATA[<p>In preparations for a upcoming blog post related to running AI workloads on Akamai Connected Cloud, I needed to deploy instances in all available Linode regions. Since there&#8217;s no way that I&#8217;ll manually create a list of regions, I thought...</p>
<p>The post <a href="https://blog.slepcevic.net/easy-way-to-deploy-linode-instances-across-all-core-regions-using-terraform/">Easy way to deploy Linode instances across all (core) regions using Terraform</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>In preparations for a upcoming blog post related to running AI workloads on Akamai Connected Cloud, I needed to deploy instances in all available Linode regions. Since there&#8217;s no way that I&#8217;ll manually create a list of regions, I thought it would be cool to use Terraforms HTTP provider to dynamically fetch the list of regions and deploy an instance to it. </p>



<p></p>



<h3 class="wp-block-heading">What’s the Plan?</h3>



<p></p>



<ol class="wp-block-list">
<li><strong>Fetch the list of regions</strong>: Use Terraform&#8217;s HTTP provider to retrieve the list of Linode regions via the Linode API.</li>



<li><strong>Deploy Instances</strong>: Use Terraform’s Linode provider to deploy instances in each of these regions.</li>



<li><strong>Grab some coffee</strong>: Sit back and relax while Terraform does the heavy lifting.</li>
</ol>



<h3 class="wp-block-heading">Pre-requisites</h3>



<p>Before we begin, make sure you have:</p>



<ul class="wp-block-list">
<li>A Linode account (If not, sign up <a href="https://www.linode.com/" target="_blank" rel="noopener" title="">here</a>).</li>



<li>A Linode API token (Grab it from your <a href="https://cloud.linode.com/profile/tokens" target="_blank" rel="noopener" title="">Linode dashboard</a>).</li>



<li>Terraform installed on your machine (Download it from <a href="https://developer.hashicorp.com/terraform/install" target="_blank" rel="noopener" title="">here</a>).</li>
</ul>



<h3 class="wp-block-heading">Step-by-Step Guide</h3>



<h4 class="wp-block-heading">Step 1: Define Providers and Variables</h4>



<p>We’ll start by defining our providers and variables. The HTTP provider will fetch the regions, and the Linode provider will deploy our instances.</p>



<p></p>



<pre class="wp-block-code"><code>provider "http" {}

variable "token" {
type = string
default = "mytoken" # Replace with your actual Linode API token
}</code></pre>



<h4 class="wp-block-heading">Step 2: Fetch Regions from Linode API.</h4>



<p>Next, let’s fetch the list of regions using the HTTP provider. We’ll decode the JSON response to extract the region IDs. </p>



<p><strong>Please note that if you uncomment the &#8220;request_headers&#8221; part, you will get a list of regions only available to your user/account. </strong> By default you will get a list of all public regions. </p>



<pre class="wp-block-code"><code>data "http" "regions" {
  url = "https://api.linode.com/v4/regions"

#   request_headers = {
#     Authorization = "Bearer ${var.token}"
#   }
}

locals {
  regions = &#91;for region in jsondecode(data.http.regions.response_body).data : region.id]
}</code></pre>



<h4 class="wp-block-heading">Step 3: Deploy Linode Instances</h4>



<p>Now comes the fun part! We’ll utilize Terraform’s &#8220;<code>for_each"</code> feature to loop through the regions and deploy a virtual machine. </p>



<pre class="wp-block-code"><code><code>provider "linode" {
  token = var.token
}

resource "linode_instance" "instances" {
  for_each = toset(local.regions)

  label    = "linode-${each.key}"
  region   = each.key
  type     = "g6-standard-1"  # Example Linode type, adjust as needed
  image    = "linode/ubuntu20.04"  # Example image, adjust as needed
  root_pass = "your_secure_password"  # Replace with a secure password
  authorized_keys = &#91;file("~/.ssh/id_rsa.pub")]  # Adjust path to your public key
}<span style="background-color: initial; font-family: inherit; font-size: inherit; color: initial;"></span></code></code></pre>



<h4 class="wp-block-heading">Step 4: Outputs</h4>



<p>Finally, let’s define some outputs to see the regions and instances we’ve created.</p>



<pre class="wp-block-code"><code><code>output "regions" {
  value = local.regions
}

output "instances" {
  value = { for instance in linode_instance.instances : instance.id => instance }
}
</code></code></pre>



<h3 class="wp-block-heading">Wrapping Up</h3>



<p>And there you have it! With just a few lines of code, we’ve automated the deployment of Linode instances across all regions. Terraform takes care of the heavy lifting, allowing you to focus on what matters most – enjoying a cup of coffee while your infrastructure magically sets itself up :D+</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="974" height="441" src="http://blog.slepcevic.net/wp-content/uploads/2024/06/Screenshot-2024-06-04-004302.png" alt="" class="wp-image-434" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/06/Screenshot-2024-06-04-004302.png 974w, https://blog.slepcevic.net/wp-content/uploads/2024/06/Screenshot-2024-06-04-004302-300x136.png 300w, https://blog.slepcevic.net/wp-content/uploads/2024/06/Screenshot-2024-06-04-004302-768x348.png 768w" sizes="auto, (max-width: 974px) 100vw, 974px" /></figure>



<p>Until next time, Alex!</p><p>The post <a href="https://blog.slepcevic.net/easy-way-to-deploy-linode-instances-across-all-core-regions-using-terraform/">Easy way to deploy Linode instances across all (core) regions using Terraform</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/easy-way-to-deploy-linode-instances-across-all-core-regions-using-terraform/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Sentiment analysis of 40 thousand movie reviews in 20 minutes using Neural Magic&#8217;s DeepSparse inference runtime and Linode virtual machines.</title>
		<link>https://blog.slepcevic.net/sentiment-analysis-of-40-thousand-movie-reviews-in-20-minutes-using-neural-magics-deepsparse-inference-runtime-and-linode/</link>
					<comments>https://blog.slepcevic.net/sentiment-analysis-of-40-thousand-movie-reviews-in-20-minutes-using-neural-magics-deepsparse-inference-runtime-and-linode/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Sat, 30 Mar 2024 22:54:00 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[DeepSparse]]></category>
		<category><![CDATA[Linode]]></category>
		<category><![CDATA[Neural Magic]]></category>
		<guid isPermaLink="false">https://blog.slepcevic.net/?p=287</guid>

					<description><![CDATA[<p>First, let me start with a word or two about DeepSparse. DeepSparse is a sparsity-aware inference runtime that delivers GPU-class performance on commodity CPUs, purely in software, anywhere. GPUs Are Not Optimal &#8211; Machine learning inference has evolved over the...</p>
<p>The post <a href="https://blog.slepcevic.net/sentiment-analysis-of-40-thousand-movie-reviews-in-20-minutes-using-neural-magics-deepsparse-inference-runtime-and-linode/">Sentiment analysis of 40 thousand movie reviews in 20 minutes using Neural Magic’s DeepSparse inference runtime and Linode virtual machines.</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>First, let me start with a word or two about DeepSparse. </p>



<p><strong>DeepSparse is a sparsity-aware inference runtime that delivers GPU-class performance on commodity CPUs, purely in software, anywhere.</strong></p>



<p><strong>GPUs Are Not Optimal</strong> &#8211; Machine learning inference has evolved over the years led by GPU advancements. GPUs are fast and powerful, but they can be expensive, have shorter life spans, and require a lot of electricity and cooling.</p>



<p>Other major problems with GPU&#8217;s, especially if you&#8217;re thinking in the context of <a href="https://www.akamai.com/newsroom/press-release/akamai-takes-cloud-computing-to-the-edge" title="">Edge computing</a>, is that they can&#8217;t be packed as densely and are power ineffective compared to CPU&#8217;s; not to mention availability these days.</p>



<p>Since Akamai recently partnered up with Neural Magic, I&#8217;ve decided to write a quick tutorial on how to easily get started with running a simple <strong>DeepSparse sentiment analysis workload</strong>. </p>



<p>In case you want more about Akamai and Neural Magic&#8217;s partnership, make sure to watch this excellent video from TFiR. It will also give you a great summary of Akamai&#8217;s Project Gecko.</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<div class="responsive-embed widescreen"><iframe loading="lazy" title="Akamai partners with Neural Magic to bring AI to edge use cases" width="1000" height="563" src="https://www.youtube.com/embed/MG45UM4SlbQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></div>
</div></figure>



<p></p>



<h3 class="wp-block-heading">What is Sentiment analysis?</h3>



<p><strong>Sentiment analysis</strong>&nbsp;(also known as&nbsp;<strong>opinion mining</strong>&nbsp;or&nbsp;<strong>emotion AI</strong>) is the use of&nbsp;<a href="https://en.wikipedia.org/wiki/Natural_language_processing">natural language processing</a>,&nbsp;<a href="https://en.wikipedia.org/wiki/Text_analytics">text analysis</a>,&nbsp;<a href="https://en.wikipedia.org/wiki/Computational_linguistics">computational linguistics</a>, and&nbsp;<a href="https://en.wikipedia.org/wiki/Biometrics">biometrics</a>&nbsp;to systematically identify, extract, quantify, and study affective states and subjective information. Sentiment analysis is widely applied to&nbsp;<a href="https://en.wikipedia.org/wiki/Voice_of_the_customer">voice of the customer</a>&nbsp;materials such as reviews and survey responses, online and social media, and healthcare materials for applications that range from&nbsp;<a href="https://en.wikipedia.org/wiki/Marketing">marketing</a>&nbsp;to&nbsp;<a href="https://en.wikipedia.org/wiki/Customer_relationship_management">customer service</a>&nbsp;to clinical medicine.&nbsp;</p>



<p>Why is DeepSparse cool? Because I&#8217;m doing analysis of 40 thousands movie reviews in 20 minutes using only <strong>TWO DUAL CORE Linode VM&#8217;s. Mind officially blown. </strong></p>



<p></p>



<p></p>



<p>Let&#8217;s do some math here; rounding it up to 120 thousand processed reviews an hour, with 2 instances and a load balancer, we can process over<strong> 86 million requests a month</strong> which will cost you a <strong>staggering 82$ <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong>. </p>



<p><strong>If you&#8217;re doing that on other cloud providers, you&#8217;re paying a five digit monthly bill for that pleasure. </strong></p>



<p></p>



<h2 class="wp-block-heading">Want to try it yourself? It&#8217;s easy!</h2>



<p>If you want to try it out on Linode, follow instructions below. </p>



<p>If you want to check out Neural Magic DeepSparse repo, head out <a href="https://github.com/neuralmagic/deepsparse" target="_blank" rel="noopener" title="">here</a>.</p>



<p><strong>Step 1.  Clone the Repository</strong>.</p>



<p>Open your terminal or command prompt and run the following command: </p>



<pre class="wp-block-code"><code>git clone https://github.com/slepix/neuralmagic-linode</code></pre>



<p>This code will deploy <strong>2 x Dedicated 4 GB</strong> virtual machines and a <strong>Nodebalancer</strong>. It will also install Neural Magic&#8217;s DeepSparse runtime as a Linux service and  install &amp; configure Nginx to proxy requests to DeepSparse server listening on 127.0.0.1:5543. </p>



<p class="has-vivid-red-color has-text-color has-link-color wp-elements-f0a0be9819cd2bc070b1912e9e812e46"><strong>WARNING: THIS IS NOT PRODUCTION GRADE SERVER CONFIGURATION!</strong></p>



<p class="has-vivid-red-color has-text-color has-link-color wp-elements-42cceec5227b00bdbbe795cf30c2587a">It&#8217;s just a POC! Secure your servers and consult Neural Magic documentation if you want to go to production. </p>



<p><strong>Step 2. </strong>&#8211; <strong>Terraform init</strong></p>



<p>Navigate to the repo using the following command: </p>



<pre class="wp-block-code"><code>cd neuralmagic-linode</code></pre>



<p>If you haven&#8217;t already installed Terraform on your machine, you can download it from the <a href="https://developer.hashicorp.com/terraform/install?product_intent=terraform" target="_blank" rel="noopener" title="">official Terraform website</a> and follow the installation instructions for your operating system.</p>



<p><strong>Step 3. </strong></p>



<p>Initialize Terraform by running:</p>



<pre class="wp-block-code"><code>terraform init</code></pre>



<p><strong>Step 4. </strong>&#8211; <strong>Configure your Linode token</strong></p>



<p>Open <strong>variables.tf </strong>file and paste in your Linode token. If you don&#8217;t know how to create a Linode PAT, check this article <strong><a href="https://www.linode.com/docs/products/tools/api/guides/manage-api-tokens/" target="_blank" rel="noopener" title="">here</a></strong>. It should look similar like the picture. You can also adjust the region while you&#8217;re here <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<pre class="wp-block-preformatted">Token in the picture is not valid. It's just an example. </pre>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="772" height="275" src="https://blog.slepcevic.net/wp-content/uploads/2024/03/tokendemo.png" alt="" class="wp-image-293" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/03/tokendemo.png 772w, https://blog.slepcevic.net/wp-content/uploads/2024/03/tokendemo-300x107.png 300w, https://blog.slepcevic.net/wp-content/uploads/2024/03/tokendemo-768x274.png 768w" sizes="auto, (max-width: 772px) 100vw, 772px" /></figure>



<p><strong>Step 5</strong> &#8211; <strong>Run Terraform apply</strong></p>



<p>After configuring your variables, you can apply the Terraform configuration by running:</p>



<pre class="wp-block-code"><code>terraform apply</code></pre>



<p>Terraform will show you a plan of the changes it intends to make. </p>



<p>Review the plan carefully, and if everything looks good, type &#8220;<code><strong>yes"</strong></code> and press Enter to apply the changes. Give it 5-6 minutes to finish everything and by visiting your Nodebalancer IP, you should be presented with a landing page for DeepSparse server API. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="518" src="https://blog.slepcevic.net/wp-content/uploads/2024/03/Screenshot-2024-03-31-233941-1024x518.png" alt="" class="wp-image-294" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/03/Screenshot-2024-03-31-233941-1024x518.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2024/03/Screenshot-2024-03-31-233941-300x152.png 300w, https://blog.slepcevic.net/wp-content/uploads/2024/03/Screenshot-2024-03-31-233941-768x388.png 768w, https://blog.slepcevic.net/wp-content/uploads/2024/03/Screenshot-2024-03-31-233941.png 1457w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p><strong>Step 6. </strong></p>



<p>After the installation is done, it&#8217;s finally time to send some data to our API and see how it performs. </p>



<p>We can do that by using <strong>curl </strong>or <strong>invoke-webrequest</strong> if you&#8217;re on Windows and using Powershell. </p>



<p><strong>CURL: </strong></p>



<pre class="wp-block-code"><code>sentence="Neural Magic &amp; Akamai are cool!"
nodebalancer="172.233.34.110" #PUT YOUR NODEBALANCER IP HERE
curl -X POST http://$nodebalancer/v2/models/sentiment_analysis/infer -H "Content-Type: application/json" -d "{\"sequences\": \"$sentence\"}"</code></pre>



<p><strong>PowerShell:</strong></p>



<p></p>



<pre class="wp-block-code"><code>$sentence = "Neural Magic &amp; Akamai are cool!"
$nodebalancer = "172.233.34.110"

$path = "v2/models/sentiment_analysis/infer"
$api = "http://$nodebalancer/$path"
$body = @{
   sequences = $sentence
} | ConvertTo-Json

(Invoke-WebRequest -Uri $api -Method Post -ContentType "application/json" -Body $body -ErrorAction Stop).content</code></pre>



<p>In both cases make sure to paste in the <strong>IP address of the Nodebalancer</strong> you deployed and modify the sentence as you wish. </p>



<h2 class="wp-block-heading">Benchmark time!</h2>



<p>In the repository, I&#8217;ve included a file called movies.csv and three files; two PowerShell and one Python file.</p>



<p><strong>movies.zip</strong> &#8211; unzip this one in the same folder where your benchmark scripts are. </p>



<p><strong>analyze.ps1</strong> &#8211; PowerShell based benchmark, sends requests in serial &#8211; not performant. </p>



<p><strong>panalyze.ps1</strong> &#8211; PowerShell based benchmark, sends requests in parallel &#8211; better performant</p>



<p><strong>pypanalyze.py</strong> &#8211; Python based benchmark, sends requests in parallel &#8211; <strong>best performer (doh!) &lt;-use this</strong></p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="581" height="153" src="http://blog.slepcevic.net/wp-content/uploads/2024/04/Screenshot-2024-04-01-014021.png" alt="" class="wp-image-327" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/04/Screenshot-2024-04-01-014021.png 581w, https://blog.slepcevic.net/wp-content/uploads/2024/04/Screenshot-2024-04-01-014021-300x79.png 300w" sizes="auto, (max-width: 581px) 100vw, 581px" /></figure>



<p>All you need to do to in order to kick off a benchmark is to update the the URL variable with your Nodebalancer IP and you&#8217;re off to the races. </p>



<h2 class="wp-block-heading">Does it scale?</h2>



<p><strong>Yes!</strong> For kicks I&#8217;ve added a third node and the same job finished in 825 seconds. Feel free to add as many nodes as you like and see what numbers you can get. Additionally, you can play with the number of workers in the Python file. </p>



<pre class="wp-block-preformatted">Note 1: python script has been written with the help of ChatGPT :) Results matched with my PowerShell version against verified smaller sample size(check note 2), so I'm gonna call it good :)
	 
Note 2: PowerShell versions don't handle some comments as they should and end up sending garbage to the API. Happens in 3% of the cases. Most probably some encoding/character issue which I couldn't be bothered to fix :)

Note3: Movies.csv file has been generated by using data from https://kaggle.com/

</pre>



<p>Cheers, </p>



<p>Alex. </p>



<p></p><p>The post <a href="https://blog.slepcevic.net/sentiment-analysis-of-40-thousand-movie-reviews-in-20-minutes-using-neural-magics-deepsparse-inference-runtime-and-linode/">Sentiment analysis of 40 thousand movie reviews in 20 minutes using Neural Magic’s DeepSparse inference runtime and Linode virtual machines.</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/sentiment-analysis-of-40-thousand-movie-reviews-in-20-minutes-using-neural-magics-deepsparse-inference-runtime-and-linode/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deploying HarperDB Docker container on Linode VM using Terraform and cloud-init</title>
		<link>https://blog.slepcevic.net/deploying-harperdb-docker-container-on-linode-vm-using-terraform-and-cloud-init/</link>
					<comments>https://blog.slepcevic.net/deploying-harperdb-docker-container-on-linode-vm-using-terraform-and-cloud-init/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Tue, 27 Feb 2024 12:45:04 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[HarperDB]]></category>
		<category><![CDATA[Linode]]></category>
		<guid isPermaLink="false">http://172.233.40.105/blog.slepcevic.net/?p=227</guid>

					<description><![CDATA[<p>This blog post is a small update to the excellent post guys from HarperDB wrote &#8211; https://www.harperdb.io/development/tutorials/deploying-harperdb-on-digital-ocean-linode-with-terraform Since Linode now support cloud-init and metadata service, I decided to extend their example by using cloud-init to do the installation of Docker...</p>
<p>The post <a href="https://blog.slepcevic.net/deploying-harperdb-docker-container-on-linode-vm-using-terraform-and-cloud-init/">Deploying HarperDB Docker container on Linode VM using Terraform and cloud-init</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>This blog post is a small update to the excellent post guys from HarperDB wrote &#8211; <a href="https://www.harperdb.io/development/tutorials/deploying-harperdb-on-digital-ocean-linode-with-terraform" target="_blank" rel="noreferrer noopener">https://www.harperdb.io/development/tutorials/deploying-harperdb-on-digital-ocean-linode-with-terraform</a></p>



<p>Since Linode now support <a href="https://www.linode.com/docs/guides/applications/configuration-management/cloud-init/">cloud-init</a> and <a href="https://www.linode.com/docs/guides/using-metadata-cloud-init-on-any-distribution/">metadata service</a>, I decided to extend their example by using cloud-init to do the installation of Docker Engine and HarperDB container. </p>



<p>All you need to do to get HarperDB running is to copy all of these files in the same folder while making sure to keep the filenames the same (<strong>harperdb.yaml</strong> at least). </p>



<p>After that, simply run Terraform init, then Terraform apply and in 2-3 minutes you should have your HarperDB instance up and running. </p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1083" height="540" src="https://blog.slepcevic.net/wp-content/uploads/2024/02/harpervscode.png" alt="This is how your folder structure should look like when you copy all the files. " class="wp-image-253" srcset="https://blog.slepcevic.net/wp-content/uploads/2024/02/harpervscode.png 1083w, https://blog.slepcevic.net/wp-content/uploads/2024/02/harpervscode-300x150.png 300w, https://blog.slepcevic.net/wp-content/uploads/2024/02/harpervscode-1024x511.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2024/02/harpervscode-768x383.png 768w" sizes="auto, (max-width: 1083px) 100vw, 1083px" /></figure>



<figure class="wp-block-pullquote has-small-font-size" style="font-style:normal;font-weight:700"><blockquote><p><strong>Please change the passwords for your Linode VM and HarperDB in the compute.tf &amp; harperdb.yaml files &lt;3</strong><br><strong> Don&#8217;t be that guy! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong></p><cite>Alex, 2024</cite></blockquote></figure>



<pre class="wp-block-code"><code>terraform init
terraform apply -var="token=YourLinodeToken"</code></pre>



<p><strong>harperdb.yaml</strong></p>



<pre class="wp-block-code"><code>#cloud-config
runcmd:
  - sudo apt-get update
  - sudo apt-get install -yq ca-certificates curl gnupg lsb-release
  - sudo install -m 0755 -d /etc/apt/keyrings
  - for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done
  - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  - sudo chmod a+r /etc/apt/keyrings/docker.gpg
  - echo "deb &#091;arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release &amp;&amp; echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null
  - sudo apt-get update
  - sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  - sudo mkdir /home/harperdb
  - sudo chmod 777 /home/harperdb
  - sudo docker run -d -v /home/harperdb:/home/harperdb/hdb -e HDB_ADMIN_USERNAME=HDB_ADMIN -e HDB_ADMIN_PASSWORD=<strong>password </strong>-p 9925:9925 -p 9926:9926 harperdb/harperdb</code></pre>



<p><strong>compute.tf</strong></p>



<pre class="wp-block-code"><code>resource "linode_instance" "harperdb" {
  image = "linode/ubuntu22.04"
  region = "nl-ams" #Pick The region you want
  type = "g6-standard-1"
  root_pass = "YourRootPassword!" #Change this :D
   metadata {
    user_data = base64encode(file("${path.module}/harperdb.yaml"))
  }
}

resource "linode_firewall" "harperdb_firewall" {
  label = "harperdb"

  inbound {
    label    = "ssh"
    action   = "ACCEPT"
    protocol = "TCP"
    ports    = "22"
    ipv4     = &#091;"0.0.0.0/0"]
    ipv6     = &#091;"::/0"]
  }

  inbound {
    label    = "harperdb"
    action   = "ACCEPT"
    protocol = "TCP"
    ports    = "9925-9926"
    ipv4     = &#091;"0.0.0.0/0"]
    ipv6     = &#091;"::/0"]
  }

  inbound_policy = "DROP"
  outbound_policy = "ACCEPT"
  linodes = &#091;linode_instance.harperdb.id]
}

terraform {
  required_providers {
    linode = {
      source = "linode/linode"
    }
  }
}

provider "linode" {
  token = var.token
}

variable "token" {
    default = ""
    type = string
}</code></pre>



<p>Alex. </p><p>The post <a href="https://blog.slepcevic.net/deploying-harperdb-docker-container-on-linode-vm-using-terraform-and-cloud-init/">Deploying HarperDB Docker container on Linode VM using Terraform and cloud-init</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/deploying-harperdb-docker-container-on-linode-vm-using-terraform-and-cloud-init/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>From zero to WordPress in less than 2 minutes on Linode using cloud-init and/or Terraform</title>
		<link>https://blog.slepcevic.net/from-zero-to-wordpress-in-less-than-2-minutes-using-linode-and-cloud-init-and-or-terraform/</link>
					<comments>https://blog.slepcevic.net/from-zero-to-wordpress-in-less-than-2-minutes-using-linode-and-cloud-init-and-or-terraform/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Fri, 20 Oct 2023 11:53:34 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[cloud-init]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Linode]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[wordpress]]></category>
		<guid isPermaLink="false">http://172.233.40.105/blog.slepcevic.net/?p=185</guid>

					<description><![CDATA[<p>Yeah, it&#8217;s true. You can get a fully running VM with installed MySQL, Apache, PHP and WordPress configured in less than 2 minutes! 1:58 to be exact 🙂 Ok, what is cloud-init in the first place? Cloud-init is a widely...</p>
<p>The post <a href="https://blog.slepcevic.net/from-zero-to-wordpress-in-less-than-2-minutes-using-linode-and-cloud-init-and-or-terraform/">From zero to WordPress in less than 2 minutes on Linode using cloud-init and/or Terraform</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Yeah, it&#8217;s true. You can get a fully running VM with installed MySQL, Apache, PHP and WordPress configured in less than 2 minutes! <strong>1:58 to be exact <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong></p>



<p><strong>Ok, what is cloud-init in the first place?</strong></p>



<p>Cloud-init is a widely used open-source package for initializing and configuring cloud instances (virtual machines or instances) in cloud computing environments. It is commonly used in infrastructure as a service (IaaS) and cloud platforms such as Akamai Connected Cloud, Amazon Web Services (AWS), Google Cloud Platform (GCP), Microsoft Azure, and various other cloud providers.</p>



<p>Cloud-init allows you to define and execute custom scripts and configuration at instance launch time or when an instance boots. It is typically provided with the cloud <a href="https://blog.slepcevic.net/linode-metadata-service/">instance&#8217;s metadata</a> during its provisioning. This metadata can include user data, which consists of cloud-init configuration in the form of a script or YAML file.</p>



<p>Key features and use cases of cloud-init include:</p>



<p><strong>Operating System Configuration</strong>: You can use cloud-init to perform various tasks like setting the hostname, configuring network interfaces, setting up users, and more.</p>



<p><strong>Package Installation</strong>: Cloud-init can be used to install software packages, libraries, or applications on the newly provisioned instance.</p>



<p><strong>User Data</strong>: You can pass user-specific data to the instance, which can be used to customize the instance&#8217;s behavior at boot time. For example, you can use it to configure software, install additional packages, or run scripts.</p>



<p><strong>Security</strong>: You can use cloud-init to set up SSH keys for secure access, set firewall rules, or perform other security-related tasks.</p>



<p><strong>Customization</strong>: Cloud-init allows you to define instance-specific customizations, making it easier to automate the setup and configuration of instances.</p>



<p><strong>Cloud Provider Agnostic</strong>: While commonly used in various cloud providers, cloud-init is not tied to a specific cloud platform. It&#8217;s available and can be used in many different environments.</p>



<p><strong>Flexibility</strong>: You can provide cloud-init configuration as a script or a YAML file, giving you flexibility in how you define the initialization and configuration process.</p>



<p></p>



<p>Ok, but how do I use it? It&#8217;s quite simple actually. </p>



<p>In this example, we install 5 packages and run a few commands to download WordPress, create a DB user, prepare wp-config file and so on. </p>



<p><strong>Please make sure to use a better password and/or a better way to deliver the credentials to the VM. Password in <em>plain </em>text is just for demo purposes and it&#8217;s just <em>plain</em> wrong (ha ha, get it! :D)!</strong></p>



<p>Log into your Linode Cloud manager interface and click on &#8220;<strong>Create Linode</strong>&#8221; button. </p>



<p><strong><em>Make sure to select a distribution which support cloud-init!</em></strong> <strong>Those are indicated by a &#8220;file&#8221; icon next to the distro name. </strong></p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="727" height="428" src="https://blog.slepcevic.net/wp-content/uploads/2023/10/cloudinit.png" alt="" class="wp-image-186" srcset="https://blog.slepcevic.net/wp-content/uploads/2023/10/cloudinit.png 727w, https://blog.slepcevic.net/wp-content/uploads/2023/10/cloudinit-300x177.png 300w" sizes="auto, (max-width: 727px) 100vw, 727px" /></figure>



<p>Next step (beside selecting the region, instance type, key and password), is to expand the &#8220;User Data&#8221; section and paste in the following code and press &#8220;Deploy&#8221;. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="262" src="https://blog.slepcevic.net/wp-content/uploads/2023/10/userdata-2-1024x262.png" alt="" class="wp-image-189" srcset="https://blog.slepcevic.net/wp-content/uploads/2023/10/userdata-2-1024x262.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2023/10/userdata-2-300x77.png 300w, https://blog.slepcevic.net/wp-content/uploads/2023/10/userdata-2-768x196.png 768w, https://blog.slepcevic.net/wp-content/uploads/2023/10/userdata-2-1280x328.png 1280w, https://blog.slepcevic.net/wp-content/uploads/2023/10/userdata-2.png 1283w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p></p>



<pre class="wp-block-code"><code>#cloud-config
packages:
  - apache2
  - mysql-server
  - php8.1
  - libapache2-mod-php8.1
  - php8.1-mysql
runcmd:
  - mkdir -p /var/www/html  # Create the /var/www/html directory if it doesn't exist
  - rm -f /var/www/html/index.html  # Remove the default index.html file
  - &#091;wget, https://wordpress.org/latest.tar.gz, -O, /tmp/wordpress.tar.gz]
  - &#091;tar, -xvzf, /tmp/wordpress.tar.gz, -C, /var/www/html]
  - mv /var/www/html/wordpress/* /var/www/html/  # Move WordPress files to the root of the web directory
  - &#091;chown, -R, www-data:www-data, /var/www/html]
  - |
    mysql -u root -e "CREATE DATABASE wordpress;"
    mysql -u root -e "CREATE USER 'wordpressuser'@'localhost' IDENTIFIED BY 'ComplexPassword123#';"
    mysql -u root -e "GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpressuser'@'localhost';"
    mysql -u root -e "FLUSH PRIVILEGES;"
  - cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php
  - sed -i 's/database_name_here/wordpress/g' /var/www/html/wp-config.php
  - sed -i 's/username_here/wordpressuser/g' /var/www/html/wp-config.php
  - sed -i 's/password_here/ComplexPassword123#/g' /var/www/html/wp-config.php
  - a2enmod php8.1  # Enable PHP module
  - systemctl restart apache2  # Restart Apache to apply the changes
</code></pre>



<p>Open your browser and navigate to the IP address of the server and less than 2 minutes after you should be greeted with a WordPress &#8220;Finish setup&#8221; page where you need to specify your email, username and password. </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="825" src="https://blog.slepcevic.net/wp-content/uploads/2023/10/wordpress-1024x825.png" alt="" class="wp-image-190" srcset="https://blog.slepcevic.net/wp-content/uploads/2023/10/wordpress-1024x825.png 1024w, https://blog.slepcevic.net/wp-content/uploads/2023/10/wordpress-300x242.png 300w, https://blog.slepcevic.net/wp-content/uploads/2023/10/wordpress-768x619.png 768w, https://blog.slepcevic.net/wp-content/uploads/2023/10/wordpress.png 1030w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p></p>



<p>You can accomplish the same thing via Terraform by using the &#8220;<strong>metadata</strong>&#8221; block and <strong>encoding your cloud-init script in base64</strong>.</p>



<pre class="wp-block-code"><code>
resource "linode_instance" "wordpressviacloudinit" {
  label = "Wordpress-via-cloudinit"
  image = "linode/ubuntu22.04"
  region = "us-iad"
  type = "g6-standard-1"
  authorized_keys = &#091;"ssh-rsa AAAA...Gw== user@example.local"]
  root_pass = "terr4form-test"
  <strong>metadata </strong>{<strong>
    user_data </strong>= "I2Nsb3VkLWNvbmZpZwpwYWNrYWdlczoKICAtIGFwYWNoZTIKICAtIG15c3FsLXNlcnZlcgogIC0gcGhwOC4xCiAgLSBsaWJhcGFjaGUyLW1vZC1waHA4LjEKICAtIHBocDguMS1teXNxbApydW5jbWQ6CiAgLSBta2RpciAtcCAvdmFyL3d3dy9odG1sICAjIENyZWF0ZSB0aGUgL3Zhci93d3cvaHRtbCBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdAogIC0gcm0gLWYgL3Zhci93d3cvaHRtbC9pbmRleC5odG1sICAjIFJlbW92ZSB0aGUgZGVmYXVsdCBpbmRleC5odG1sIGZpbGUKICAtIFt3Z2V0LCBodHRwczovL3dvcmRwcmVzcy5vcmcvbGF0ZXN0LnRhci5neiwgLU8sIC90bXAvd29yZHByZXNzLnRhci5nel0KICAtIFt0YXIsIC14dnpmLCAvdG1wL3dvcmRwcmVzcy50YXIuZ3osIC1DLCAvdmFyL3d3dy9odG1sXQogIC0gbXYgL3Zhci93d3cvaHRtbC93b3JkcHJlc3MvKiAvdmFyL3d3dy9odG1sLyAgIyBNb3ZlIFdvcmRQcmVzcyBmaWxlcyB0byB0aGUgcm9vdCBvZiB0aGUgd2ViIGRpcmVjdG9yeQogIC0gW2Nob3duLCAtUiwgd3d3LWRhdGE6d3d3LWRhdGEsIC92YXIvd3d3L2h0bWxdCiAgLSB8CiAgICBteXNxbCAtdSByb290IC1lICJDUkVBVEUgREFUQUJBU0Ugd29yZHByZXNzOyIKICAgIG15c3FsIC11IHJvb3QgLWUgIkNSRUFURSBVU0VSICd3b3JkcHJlc3N1c2VyJ0AnbG9jYWxob3N0JyBJREVOVElGSUVEIEJZICdDb21wbGV4UGFzc3dvcmQxMjMjJzsiCiAgICBteXNxbCAtdSByb290IC1lICJHUkFOVCBBTEwgUFJJVklMRUdFUyBPTiB3b3JkcHJlc3MuKiBUTyAnd29yZHByZXNzdXNlcidAJ2xvY2FsaG9zdCc7IgogICAgbXlzcWwgLXUgcm9vdCAtZSAiRkxVU0ggUFJJVklMRUdFUzsiCiAgLSBjcCAvdmFyL3d3dy9odG1sL3dwLWNvbmZpZy1zYW1wbGUucGhwIC92YXIvd3d3L2h0bWwvd3AtY29uZmlnLnBocAogIC0gc2VkIC1pICdzL2RhdGFiYXNlX25hbWVfaGVyZS93b3JkcHJlc3MvZycgL3Zhci93d3cvaHRtbC93cC1jb25maWcucGhwCiAgLSBzZWQgLWkgJ3MvdXNlcm5hbWVfaGVyZS93b3JkcHJlc3N1c2VyL2cnIC92YXIvd3d3L2h0bWwvd3AtY29uZmlnLnBocAogIC0gc2VkIC1pICdzL3Bhc3N3b3JkX2hlcmUvQ29tcGxleFBhc3N3b3JkMTIzIy9nJyAvdmFyL3d3dy9odG1sL3dwLWNvbmZpZy5waHAKICAtIGEyZW5tb2QgcGhwOC4xICAjIEVuYWJsZSBQSFAgbW9kdWxlCiAgLSBzeXN0ZW1jdGwgcmVzdGFydCBhcGFjaGUyICAjIFJlc3RhcnQgQXBhY2hlIHRvIGFwcGx5IHRoZSBjaGFuZ2VzCg=="
  }
  group = "foo"
  tags = &#091; "foo" ]
  swap_size = 512
  private_ip = false
}</code></pre>



<p>Of course, you can use cloud-init for pretty much anything you want but the ideal usecase would be bootstrapping your instance so your configuration management tool can take over after Terraform creates it. </p>



<p>Until next time!</p>



<p>Cheers, Alex. </p><p>The post <a href="https://blog.slepcevic.net/from-zero-to-wordpress-in-less-than-2-minutes-using-linode-and-cloud-init-and-or-terraform/">From zero to WordPress in less than 2 minutes on Linode using cloud-init and/or Terraform</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/from-zero-to-wordpress-in-less-than-2-minutes-using-linode-and-cloud-init-and-or-terraform/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Linode&#8217;s Metadata service is live!</title>
		<link>https://blog.slepcevic.net/linode-metadata-service/</link>
					<comments>https://blog.slepcevic.net/linode-metadata-service/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Wed, 13 Sep 2023 14:04:00 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">http://172.233.40.105/blog.slepcevic.net/?p=177</guid>

					<description><![CDATA[<p>Linode finally introduced an internal metadata service! &#60;3 I&#8217;m sure all of you have been in a situation where after deploying Compute Instances, it’s almost always needed to perform additional configuration before your server is ready to do any real...</p>
<p>The post <a href="https://blog.slepcevic.net/linode-metadata-service/">Linode’s Metadata service is live!</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p><strong>Linode finally introduced an internal metadata service! &lt;3</strong></p>



<p></p>



<p>I&#8217;m sure all of you have been in a situation where after deploying Compute Instances, it’s almost always needed to perform additional configuration before your server is ready to do any real work. </p>



<p>This configuration might include creating a new user, adding an SSH key, installing software, etc&#8230;it could also include more complicated tasks like configuring a web server or other software that runs on the instance. Performing these tasks manually can be error prone, slow and is not scalable. </p>



<p>To automate this process, Linode offers two provisioning automation tools: Metadata/cloudinit and <a href="https://www.linode.com/docs/products/tools/stackscripts/">StackScripts</a>.</p>



<p></p>



<p><strong>Cool, but what is Linode&#8217;s Metadata service? Well, in a nutshell it&#8217;s an API which is accessible only within your instance, nothing more <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></strong></p>



<p>While the Metadata service is designed to be consumed by <a href="https://cloudinit.readthedocs.io/en/latest/" target="_blank" rel="noreferrer noopener">cloud-init</a>, there are no barriers in using it without cloud-init and with any other software/script you can think of. If your software can send and read http requests, it can use Linode&#8217;s metadata service.  </p>



<p>This allows you to use the same tools across multiple cloud providers enabling you to be really flexible on where and how you run your workloads. </p>



<p></p>



<p>One of the great use-cases for metadata is to dynamically configure your environment based on instance tags or some other parameters. </p>



<p>Let&#8217;s take this example; we have our dev and production environment and we want to make sure that the VM which we deployed is configured in the same way, just with different user data (test database vs a production database). Your deployment pipeline process can query the instance&#8217;s metadata service, read the tags and instantly know that it&#8217;s deploying to a test environment and which database to use. </p>



<p>Other use-case is for bootstrapping your servers and installing some configuration management agents like Chef or similar. </p>



<p>The Metadata service provides both <em>instance data</em> and optional <em>user data</em>, both of which are explained below:</p>



<ul class="wp-block-list">
<li><strong>Instance data:</strong> The instance data includes information about the Compute Instance, including its label, plan size, region, host identifier, tags and more.</li>



<li><strong>User data:</strong>&nbsp;User data is one of the most powerful features of the Metadata service and allows you to define your desired system configuration, including creating users, installing software, configuring settings, and more. User data is supplied by the user when deploying, rebuilding, or cloning a Compute Instance. This user data can be written as a cloud-config file, or it can be any script that can be executed on the target distribution image, such as a bash script.User data can be submitted directly in the Cloud Manager, Linode CLI, or Linode API. It’s also often programmatically provided through IaC (Infrastructure as Code) provisioning tools like&nbsp;<a href="https://www.linode.com/docs/guides/how-to-build-your-infrastructure-using-terraform-and-linode/">Terraform</a>.</li>
</ul>



<p>Ok, how do I use metadata service? It&#8217;s really quite simple</p>



<ol class="wp-block-list">
<li>Log into the instance which is running an OS image which supports metadata service</li>



<li>Generate your API token using the following command</li>
</ol>



<pre class="wp-block-code"><code>export TOKEN=$(curl -X PUT -H "Metadata-Token-Expiry-Seconds: 3600" http://169.254.169.254/v1/token)</code></pre>



<p>This will put the authentication token into a TOKEN variable. </p>



<p>3. Fetch the data</p>



<pre class="wp-block-code"><code>#Instance info
curl -H "Metadata-Token: $TOKEN" http://169.254.169.254/v1/instance
#Network info
curl -H "Metadata-Token: $TOKEN" http://169.254.169.254/v1/network
#User data
curl -H "Metadata-Token: $TOKEN" http://169.254.169.254/v1/user-data | base64 --decode</code></pre>



<p>What data do I get back? </p>



<pre class="wp-block-code"><code>#Instance info
root@localhost:~# curl -H "Metadata-Token: $TOKEN" http://169.254.169.254/v1/instance
backups.enabled: false
host_uuid: 85815b0f16cfa8b12aa12a36530476e701111111
id: 51048111
label: jumphost-us-iad
region: us-iad
specs.disk: 25600
specs.gpus: 0
specs.memory: 1024
specs.transfer: 1000
specs.vcpus: 1
tags: app:jumphost
tags: region:us-iad
tags: stage:dev
type: g6-nanode-1

#Network info
root@localhost:~# curl -H "Metadata-Token: $TOKEN" http://169.254.169.254/v1/network
ipv4.public: 172.233.197.127/32
ipv6.link_local: fe80::f03c:93ff:fe56:3512/128
ipv6.slaac: 2600:3c05::f03c:93ff:fe56:3512/128
</code></pre>



<p>Cheers, Alex!</p><p>The post <a href="https://blog.slepcevic.net/linode-metadata-service/">Linode’s Metadata service is live!</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/linode-metadata-service/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to deploy a DHCP server in a Linode VLAN</title>
		<link>https://blog.slepcevic.net/how-to-deploy-a-dhcp-server-in-a-linode-vlan/</link>
					<comments>https://blog.slepcevic.net/how-to-deploy-a-dhcp-server-in-a-linode-vlan/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Fri, 08 Sep 2023 09:43:00 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Linode]]></category>
		<category><![CDATA[Terraform]]></category>
		<guid isPermaLink="false">http://172.233.40.105/blog.slepcevic.net/?p=171</guid>

					<description><![CDATA[<p>When a VLAN is assigned to a network interface and given an IPAM address, the Compute Instance should automatically be able to communicate over that private network. This is due to Network Helper, which is enabled by default on most instances....</p>
<p>The post <a href="https://blog.slepcevic.net/how-to-deploy-a-dhcp-server-in-a-linode-vlan/">How to deploy a DHCP server in a Linode VLAN</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>When a VLAN is assigned to a network interface and given an IPAM address, the Compute Instance should automatically be able to communicate over that private network. This is due to <a href="https://www.linode.com/docs/products/compute/compute-instances/guides/network-helper/">Network Helper</a>, which is enabled by default on most instances. For compatible distributions, Network Helper adjusts the internal network configuration files. Any network interfaces defined in the Compute Instance’s selected <a href="https://www.linode.com/docs/products/compute/compute-instances/guides/configuration-profiles/">Configuration Profile</a> (including those with VLANs attached) are automatically configured.</p>



<p>While Network Helper is really useful, it&#8217;s becomes a problem when you deploy an instance serving as an internet gateway in your VLAN. In order to assign an IP address, DNS and a gateway, we need to deploy a DHCP server. Network Helper cannot set DNS and gateway settings. </p>



<p></p>



<p>Please have in mind that you can also install the DHCP server on your IGW (Internet gateway) instance as well, but for the purposes of this post, we will assume that we have a standalone DHCP server. </p>



<p></p>



<p>First thing we need to do is to create a Linode StackScript which we will use to automatically install and configure our DHCP server. </p>



<pre class="wp-block-code"><code>#!/bin/bash
#&lt;UDF name="DEFLEASETIME" Label="Default lease time" example="3600" /&gt;
#&lt;UDF name="MAXLEASETIME" Label="Max lease time" example="14400" /&gt;
#&lt;UDF name="SUBNET" Label="Subnet" example="10.10.10.0" /&gt;
#&lt;UDF name="NETMASK" Label="Netmask" example="255.255.255.0" /&gt;
#&lt;UDF name="STARTRANGE" Label="Start range" example="10.10.10.10" /&gt;
#&lt;UDF name="ENDRANGE" Label="End range" example="10.10.10.250"/&gt;
#&lt;UDF name="ROUTER" Label="Router" example="10.10.10.1" /&gt;
#&lt;UDF name="DNS1" Label="DNS1" example="10.10.10.2" /&gt;
#&lt;UDF name="DNS2" Label="DNS2" example="10.10.10.3" /&gt;
apt update -y
apt install -y isc-dhcp-server
mv /etc/dhcp/dhcpd.conf{,.backup}
cat &gt; /etc/dhcp/dhcpd.conf &lt;&lt; EOF
default-lease-time $DEFLEASETIME;
max-lease-time $MAXLEASETIME;
authoritative;
 
subnet $SUBNET netmask $NETMASK {
 range $STARTRANGE $ENDRANGE;
 option routers $ROUTER;
 option domain-name-servers $DNS1, $DNS2;
}
EOF
sed -i 's/INTERFACESv4=""/INTERFACESv4="eth1"/' /etc/default/isc-dhcp-server
systemctl restart isc-dhcp-server.service
</code></pre>



<p>After we&#8217;ve got our StackScript <a href="https://www.linode.com/docs/products/tools/stackscripts/guides/create/">created</a>, we can deploy a VM from it by clicking on &#8220;Deploy New Linode&#8221; button and filling out all the required details. Make sure that you assign the virtual machine to the VLAN you are using in your region. </p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="578" height="863" src="https://blog.slepcevic.net/wp-content/uploads/2023/10/dhcpblog.png" alt="" class="wp-image-172" srcset="https://blog.slepcevic.net/wp-content/uploads/2023/10/dhcpblog.png 578w, https://blog.slepcevic.net/wp-content/uploads/2023/10/dhcpblog-201x300.png 201w" sizes="auto, (max-width: 578px) 100vw, 578px" /></figure>



<p>You can use default settings for &#8220;<strong>Default lease time</strong>&#8221; and &#8220;<strong>Max lease time</strong>&#8220;, just make sure to adjust the &#8220;<strong>Subnet</strong>&#8221; and mask to match the ones you&#8217;re using in your VLAN. </p>



<p>We can also use Terraform to create our Stackscript by using &#8220;<strong>linode_stackscript</strong>&#8221; resource &#8211; https://registry.terraform.io/providers/linode/linode/latest/docs/resources/stackscript</p>



<p></p>



<p>For details on how to use Terraform to deploy instance from a StackScript, check out this blog post on how to use &#8220;<strong>stackscript_data</strong>&#8221; block to provide StackScript parameters &#8211; <a href="https://blog.slepcevic.net/deploying-linode-marketplace-stackscripts-with-terraform/">https://blog.slepcevic.net/deploying-linode-marketplace-stackscripts-with-terraform/</a></p>



<p></p>



<p>Cheers, Alex. </p>



<p></p><p>The post <a href="https://blog.slepcevic.net/how-to-deploy-a-dhcp-server-in-a-linode-vlan/">How to deploy a DHCP server in a Linode VLAN</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/how-to-deploy-a-dhcp-server-in-a-linode-vlan/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deploying Linode Marketplace StackScripts with Terraform</title>
		<link>https://blog.slepcevic.net/deploying-linode-marketplace-stackscripts-with-terraform/</link>
					<comments>https://blog.slepcevic.net/deploying-linode-marketplace-stackscripts-with-terraform/#respond</comments>
		
		<dc:creator><![CDATA[Alesandro Slepčević]]></dc:creator>
		<pubDate>Thu, 29 Jun 2023 08:22:00 +0000</pubDate>
				<category><![CDATA[Akamai Connected Cloud]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Linode]]></category>
		<category><![CDATA[linode-cli]]></category>
		<category><![CDATA[Terraform]]></category>
		<guid isPermaLink="false">http://172.233.40.105/blog.slepcevic.net/?p=146</guid>

					<description><![CDATA[<p>Recently, I needed to deploy a 3 node Redis Cluster from Linode&#8217;s Marketplace. Quick glance at Linode&#8217;s Terraform provider shows that we can deploy instances using StackScripts, but in order to do that, we need to specify the StackScript ID....</p>
<p>The post <a href="https://blog.slepcevic.net/deploying-linode-marketplace-stackscripts-with-terraform/">Deploying Linode Marketplace StackScripts with Terraform</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Recently, I needed to deploy a 3 node Redis Cluster from Linode&#8217;s Marketplace. </p>



<p>Quick glance at Linode&#8217;s Terraform provider shows that we can deploy instances using StackScripts, but in order to do that, we need to specify the StackScript ID. If we are deploying from our own StackScript, it&#8217;s easy, you just reference it like this and you&#8217;re good to go.</p>



<pre class="wp-block-code"><code>resource "linode_stackscript" "foo" {
  label = "foo"
  description = "Installs a Package"
  script = &lt;&lt;EOF
#!/bin/bash
# &lt;UDF name="package" label="System Package to Install" example="nginx" default=""&gt;
apt-get -q update &amp;&amp; apt-get -q -y install $PACKAGE
EOF
  images = &#091;"linode/ubuntu18.04", "linode/ubuntu16.04lts"]
  rev_note = "initial version"
}

resource "linode_instance" "foo" {
  image  = "linode/ubuntu18.04"
  label  = "foo"
  region = "us-east"
  type   = "g6-nanode-1"
  authorized_keys    = &#091;"..."]
  root_pass      = "..."

  <strong>stackscript_id = linode_stackscript.foo.id</strong>
  stackscript_data = {
    "package" = "nginx"
  }
}</code></pre>



<p>&#8220;Problem&#8221; comes when we want to deploy a product from the marketplace, in order to do that we need to collect a few things first. </p>



<ol class="wp-block-list">
<li>ID of the StackScript you want to deploy</li>



<li>List of supported OS images</li>



<li>Check which variables we need to provide to the StackScript. </li>
</ol>



<p>Step 1 &#8211; Fetching the StackScript ID. In this case, I&#8217;ll do it using linode-cli, but you&#8217;re free to use any other method</p>



<pre class="wp-block-code"><code>linode-cli stackscripts list --label "Redis Sentinel Cluster One-Click"
</code></pre>



<p>Output of this command looks like this</p>



<p><img loading="lazy" decoding="async" width="958" height="161" class="wp-image-150" style="width: 1000px" src="https://blog.slepcevic.net/wp-content/uploads/2023/07/Screenshot-2023-07-03-100015.png" alt="" srcset="https://blog.slepcevic.net/wp-content/uploads/2023/07/Screenshot-2023-07-03-100015.png 958w, https://blog.slepcevic.net/wp-content/uploads/2023/07/Screenshot-2023-07-03-100015-300x50.png 300w, https://blog.slepcevic.net/wp-content/uploads/2023/07/Screenshot-2023-07-03-100015-768x129.png 768w" sizes="auto, (max-width: 958px) 100vw, 958px" /></p>



<p>From here, we need to write down the ID of the script, and check the list of supported images. In this case, I&#8217;ll deploy a stackscript with the ID 1132204 which is owned by Linode. </p>



<p>Next step is to check which variables we need to provide to the StackScript. We can easily see that by running the following Powershell command:</p>



<pre class="wp-block-code"><code>$stackscripts = ((wget https://cloud.linode.com/api/v4/linode/stackscripts?page_size=500).Content | convertfrom-json)
$stackscripts.data | where {$_.id -like "1132204"} | select -expand user_defined_fields
name                   label
----                   -----
token_password         Your Linode API token
sudo_username          The limited sudo user to be created in the cluster
sslheader              SSL Information
country_name           Details for self-signed SSL certificates: Country or Region
state_or_province_name State or Province
locality_name          Locality
organization_name      Organization
email_address          Email Address
ca_common_name         CA Common Name
common_name            Common Name
clusterheader          Cluster Settings
add_ssh_keys           Add Account SSH Keys to All Nodes?
cluster_size           Redis cluster size</code></pre>



<p>And finally put all of those variables into our Terraform code, which in end looks something like this: </p>



<pre class="wp-block-code"><code>resource "linode_instance" "redis" {
        image = "linode/ubuntu22.04"
        label = "RedisCluster"
        group = "Redis"
        tags = &#091; "stage:dev" ]
        region = "eu-central"
        type = "g6-standard-1"
        authorized_users = &#091; "yourUsername" ]
        root_pass = "SuperRandomPassW0rd.123!"
<strong>        stackscript_id = <em>1132204</em>
        stackscript_data = {
            "token_password" = "yourLinodeToken"
            "sudo_username" = "myuser"
            "sslheader" = "Yes" #Default YES
            "country_name" = "NL"  #Two letter country code
            "state_or_province_name" = "South Holland" 
            "locality_name" = "Rotterdam" 
            "organization_name" = "Org Name" 
            "email_address" = "yourEmail@here.com" 
            "ca_common_name" = "Redis CA" 
            "clusterheader" = "Yes" 
            "add_ssh_keys" = "no" #yes or no
            "cluster_size" = "3" #3 or 5</strong>
        }
}
</code></pre>



<p>Notice we are required to provide our Linode token in order to deploy this cluster; this can be the same token you&#8217;re using for your existing Terraform code, so you can simple reference a environment variable in your code and off you go <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>Cheers, Alex. </p><p>The post <a href="https://blog.slepcevic.net/deploying-linode-marketplace-stackscripts-with-terraform/">Deploying Linode Marketplace StackScripts with Terraform</a> first appeared on <a href="https://blog.slepcevic.net">Architect the cloud</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://blog.slepcevic.net/deploying-linode-marketplace-stackscripts-with-terraform/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 
Lazy Loading (feed)

Served from: blog.slepcevic.net @ 2026-01-03 06:04:40 by W3 Total Cache
-->