<?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>Cloud Archives - Albert Nogués</title>
	<atom:link href="https://www.albertnogues.com/tag/cloud/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.albertnogues.com/tag/cloud/</link>
	<description>Data and Cloud Freelancer</description>
	<lastBuildDate>Wed, 22 Nov 2023 10:18:52 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://www.albertnogues.com/wp-content/uploads/2020/12/cropped-cropped-AlbertLogo2-32x32.png</url>
	<title>Cloud Archives - Albert Nogués</title>
	<link>https://www.albertnogues.com/tag/cloud/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Databricks query federation with Snowflake. Easy and Fast!</title>
		<link>https://www.albertnogues.com/databricks-query-federation-with-snowflake-easy-and-fast/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=databricks-query-federation-with-snowflake-easy-and-fast</link>
		
		<dc:creator><![CDATA[Albert]]></dc:creator>
		<pubDate>Tue, 31 Jan 2023 12:15:05 +0000</pubDate>
				<category><![CDATA[BigData]]></category>
		<category><![CDATA[Databricks]]></category>
		<category><![CDATA[Snowflake]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[databricks]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[snowflake]]></category>
		<category><![CDATA[spark]]></category>
		<category><![CDATA[sql]]></category>
		<guid isPermaLink="false">https://www.albertnogues.com/?p=1757</guid>

					<description><![CDATA[<p>Introduction In the same way that is possible to read and write data from snowflake inside databricks, its also possible to use databricks with query federation against diverse SQL engines, including snowflake. The current supported engines are: We are going to demonstrate how it works with Snowflake. We will first create a table in databricks, &#8230; </p>
<p>The post <a href="https://www.albertnogues.com/databricks-query-federation-with-snowflake-easy-and-fast/">Databricks query federation with Snowflake. Easy and Fast!</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">Introduction</h2>



<p>In the same way that is possible to read and write data from snowflake inside databricks, its also possible to use databricks with query federation against diverse SQL engines, including <a href="http://www.snowflake.com" target="_blank" rel="noopener" title="snowflake">snowflake</a>. The current supported engines are:</p>



<ul class="wp-block-list">
<li><a href="https://docs.databricks.com/query-federation/postgresql.html">PostgreSQL</a></li>



<li><a href="https://docs.databricks.com/query-federation/mysql.html">MySQL</a></li>



<li><a href="https://docs.databricks.com/query-federation/snowflake.html">Snowflake</a></li>



<li><a href="https://docs.databricks.com/query-federation/redshift.html">Redshift</a></li>



<li><a href="https://docs.databricks.com/query-federation/synapse.html">Synapse</a></li>



<li><a href="https://docs.databricks.com/query-federation/sql-server.html">SQL Server</a></li>
</ul>



<p>We are going to demonstrate how it works with Snowflake. We will first create a table in databricks, it can be a delta table stored in the data lake, or an unmanaged table pointing to a set of files (External Table) or anything in between.</p>



<h2 class="wp-block-heading">Creating the required resources</h2>



<p>I will go to databricks and run the following:</p>



<pre class="wp-block-code"><code>CREATE OR REPLACE TABLE default.DATABRICKS_ALBERT(
NAME STRING,
SEX STRING);

INSERT INTO default.DATABRICKS_ALBERT(NAME, SEX) VALUES ('Albert','Male');</code></pre>



<p>This process can either be done from the Data Engineering persona or the SQL persona. I created it first from the data engineering part.</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="558" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-3-1024x558.png" alt="" class="wp-image-1762" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-3-1024x558.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-3-300x164.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-3-768x419.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-3-110x60.png 110w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-3.png 1332w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now we go to snowflake and create a second table which we want to join:</p>



<pre class="wp-block-code"><code>CREATE TABLE SANDBOX.DEFAULT.DATABRICKS_FEDERATED(
NAME STRING,
AGE INTEGER);

INSERT INTO SANDBOX.DEFAULT.DATABRICKS_FEDERATED (NAME, AGE) VALUES ('Albert', 37);</code></pre>



<p>And it gets created succesfully:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="433" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-1-1024x433.png" alt="" class="wp-image-1759" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-1-1024x433.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-1-300x127.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-1-768x325.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-1-142x60.png 142w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-1.png 1189w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Now we can stay in the data engineering persona or go to databricks SQL and we create the virtual table that will create the link with the table in snowflake. This will do the mapping:</p>



<pre class="wp-block-code"><code>CREATE TABLE MY_TABLE
USING snowflake
OPTIONS(
dbtable 'YourTable',
sfURL 'yourURL.snowflakecomputing.com', --You can use privatelink if you have one
sfUser 'YourUser',
sfPassword 'YourPassword',
sfDatabase 'YourDB', --You can use a secret scope like: secret('scope_name', 'pwd_entry'),
sfSchema 'YourSchema',
sfWarehouse 'YourSnowflakeWarehouse'
);</code></pre>



<p>In the Databricks SQL:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="482" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-4-1024x482.png" alt="" class="wp-image-1763" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-4-1024x482.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-4-300x141.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-4-768x361.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-4-1536x723.png 1536w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-4-127x60.png 127w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-4.png 1891w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>In The Data Engineering:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="646" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-5-1024x646.png" alt="" class="wp-image-1764" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-5-1024x646.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-5-300x189.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-5-768x484.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-5-1536x968.png 1536w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-5-95x60.png 95w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-5.png 1702w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<h2 class="wp-block-heading">Glueing it up together</h2>



<p>If you use Databricks SQL I couldn’t make it work with the STARTER ENDPOINT so be sure to use a normal WAREHOUSE to avoid any errors. In my case i created an XS warehouse, but now i can run a query fetching data from both tables:</p>
</blockquote>



<pre class="wp-block-code"><code>select a.name, a.sex, b.age
FROM default.DATABRICKS_ALBERT a , default.SNOWFLAKE_ALBERT b
where a.name=b.name</code></pre>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="884" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-6-1024x884.png" alt="" class="wp-image-1765" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-6-1024x884.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-6-300x259.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-6-768x663.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-6-70x60.png 70w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-6.png 1081w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>And in the Data Engineering Persona:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="679" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-7-1024x679.png" alt="" class="wp-image-1766" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-7-1024x679.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-7-300x199.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-7-768x509.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-7-1536x1018.png 1536w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-7-91x60.png 91w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-7.png 1785w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>And of course you can use spark.sql with python or any other language to query the table as well:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="383" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-8-1024x383.png" alt="" class="wp-image-1767" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-8-1024x383.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-8-300x112.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-8-768x288.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-8-1536x575.png 1536w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-8-160x60.png 160w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-8.png 1811w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Or directly with Dataframes treating the federated table as any other table in the catalog:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="301" src="https://www.albertnogues.com/wp-content/uploads/2023/01/image-9-1024x301.png" alt="" class="wp-image-1768" srcset="https://www.albertnogues.com/wp-content/uploads/2023/01/image-9-1024x301.png 1024w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-9-300x88.png 300w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-9-768x226.png 768w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-9-1536x452.png 1536w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-9-204x60.png 204w, https://www.albertnogues.com/wp-content/uploads/2023/01/image-9.png 1856w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Hope this clears your way and helps you integrate data from different sources without having to use a virtual metadata layer.</p>
<p>The post <a href="https://www.albertnogues.com/databricks-query-federation-with-snowflake-easy-and-fast/">Databricks query federation with Snowflake. Easy and Fast!</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Smallest Analytical Platform Ever!</title>
		<link>https://www.albertnogues.com/smallest-analytical-platform-ever/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=smallest-analytical-platform-ever</link>
		
		<dc:creator><![CDATA[Albert]]></dc:creator>
		<pubDate>Sat, 07 May 2022 08:38:12 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Databricks]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Spark]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[databricks]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[spark]]></category>
		<guid isPermaLink="false">https://www.albertnogues.com/?p=1440</guid>

					<description><![CDATA[<p>I&#8217;ve started working on some of my free time in a project to build the smallest useful analytics platform on the cloud (starting with azure). The purpose is to use it a sa PoC to show to colleagues, managers, prospective customers or just to have fun and play It&#8217;s publicly available on my github repo &#8230; </p>
<p>The post <a href="https://www.albertnogues.com/smallest-analytical-platform-ever/">Smallest Analytical Platform Ever!</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;ve started working on some of my free time in a project to build the smallest useful analytics platform on the cloud (starting with azure).</p>



<p>The purpose is to use it a sa PoC to show to colleagues, managers, prospective customers or just to have fun and play</p>



<p>It&#8217;s publicly available on my github repo and any collaboration is welcome. You can fork it, improve it, send PR&#8217;s and do whatever you want!</p>



<p>The first version will run solely on azure. The objective is to show the following technologies/disciplines:</p>



<p>* Infrastructure as a Code (IaaC), by using Terraform</p>



<p>* Cloud architecture anc Cloud Ops by using an azure cloud environment</p>



<p>* Data Engineering by using a Spark powered Databricks Notebook and an ADF Pipeline (future)</p>



<p>* DevOps to trigger some pipelines based on changes (future)</p>



<p>* Basic Security concepts (keyvault, service principals, least privileged rbac accesses&#8230;)</p>



<p>* FinOps keeping the costs at minimum and choosing the proper tools for the job</p>



<p>* Reporting and Dashboarding on data in the platform</p>



<p>* Data management: We will use an adls storage account and azure sql db</p>



<p>TOOLS:</p>



<p>* Terraform to deploy all the infra as a code</p>



<p>* Azure Cloud to host our resources</p>



<p>You have the code plus all the information on my github repo:</p>



<p><a href="https://github.com/anogues/ProjectZ">https://github.com/anogues/ProjectZ</a></p>



<p></p>
<p>The post <a href="https://www.albertnogues.com/smallest-analytical-platform-ever/">Smallest Analytical Platform Ever!</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Implementing CI/CD in Databricks with Azure DevOps (Part 1)</title>
		<link>https://www.albertnogues.com/implementing-ci-cd-in-databricks-with-azure-devops-part-1/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=implementing-ci-cd-in-databricks-with-azure-devops-part-1</link>
		
		<dc:creator><![CDATA[Albert]]></dc:creator>
		<pubDate>Sat, 30 Apr 2022 15:10:29 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Databricks]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Spark]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[databricks]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[spark]]></category>
		<guid isPermaLink="false">https://www.albertnogues.com/?p=1416</guid>

					<description><![CDATA[<p>There are many ways to implement some CI/CD with Databricks. We can use Azure DevOps, Github+Github Actions or any other combination of tools, including the dbx tool. But an easy way to just copy notebooks between workspaces can be implemented easily with Azure DevOps. We are going to use the git repos capability of Azure &#8230; </p>
<p>The post <a href="https://www.albertnogues.com/implementing-ci-cd-in-databricks-with-azure-devops-part-1/">Implementing CI/CD in Databricks with Azure DevOps (Part 1)</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>There are many ways to implement some CI/CD with Databricks. We can use Azure DevOps, Github+Github Actions or any other combination of tools, including the <a href="https://dbx.readthedocs.io/en/latest/templates/python_basic.html#project-file-structure" target="_blank" rel="noreferrer noopener">dbx tool</a>.</p>



<p>But an easy way to just copy notebooks between workspaces can be implemented easily with Azure DevOps.</p>



<p>We are going to use the git repos capability of Azure Databricks, so when a new code change is commited in a notebook an Azure DevOps pipeline will trigger the transport copy of the workbook from the first Databricks workspace (in our case a NonProd workspace) to the target one, again, in our case, the Prod workspace.</p>



<p>To achieve this we will use some more components from the Azure ecosystem, including the use of Keyvaults to keep all our secrets stored safely. The list of prerequisites is the following:</p>



<ul class="wp-block-list"><li>Two Databricks workspaces, one our source workspace (NonProd) and another, our Production one.</li><li>An Azure Keyvault (or two if we want to segregate the environments)</li><li>Azure Databricks repository configured at least in our source workspace, so when the change is commited we can triger the pipeline that will fetch the notebook and transport it to the prod workspace</li><li>Access to Azure DevOps (Something similar can be implemented with Github + Github Actions)</li></ul>



<p>Lets see how to implement it. First we need to make sure git repos in enabled our source workspace. We can verify by login with an admin privileged user to our workspace and make sure the option is checked as follows:</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD1-924x1024.png" alt="" class="wp-image-1418" width="687" height="760" srcset="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD1-924x1024.png 924w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD1-271x300.png 271w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD1-768x851.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD1-54x60.png 54w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD1.png 1072w" sizes="auto, (max-width: 687px) 100vw, 687px" /><figcaption>Fig 1. Make sure that github repos is enabled in our workspace.</figcaption></figure>



<p>Secondly, we go to <a href="https://azure.microsoft.com/en-us/services/devops/" target="_blank" rel="noreferrer noopener">Azure DevOps services</a> and we create a new project. I&#8217;ve called it DatabricksCICD but feel free to call it whatever you need:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="714" src="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD2-1024x714.png" alt="" class="wp-image-1419" srcset="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD2-1024x714.png 1024w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD2-300x209.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD2-768x536.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD2-86x60.png 86w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD2.png 1531w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Fig 2. Create a new repo and initialize it</figcaption></figure>



<p>Once created we take the details for cloning our repo and copying them. We go to our databricks workspace and then we look for the Repos option on the left, and add a new repository. We need to paste the url to clone our newle Azure DevOps created repository:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="319" src="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD3-1024x319.png" alt="" class="wp-image-1420" srcset="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD3-1024x319.png 1024w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD3-300x93.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD3-768x239.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD3-1536x478.png 1536w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD3-2048x637.png 2048w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD3-193x60.png 193w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Fig 3. Cloning our Azure DevOps Repository</figcaption></figure>



<p>Once we linked our Databricks workspace with our DevOps repo, now we can create a new notebook. In the same Repos section, click on the down arrow to create a new notebook, as shown below:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="889" height="373" src="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD4.png" alt="" class="wp-image-1421" srcset="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD4.png 889w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD4-300x126.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD4-768x322.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD4-143x60.png 143w" sizes="auto, (max-width: 889px) 100vw, 889px" /><figcaption>Fig 4.  Creating a new notebook.</figcaption></figure>



<p>The content of the notebook, you can put anything you want. I&#8217;m writing a print(&#8220;Hello from Albert&#8221;) statement. We will not run it, we just want to show it&#8217;s possible to transport it. Once done, click on the save now in the revision tab:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="73" src="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD5-1024x73.png" alt="" class="wp-image-1423" srcset="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD5-1024x73.png 1024w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD5-300x21.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD5-768x55.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD5-1536x110.png 1536w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD5-2048x146.png 2048w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD5-600x43.png 600w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Fig 5. Saving our changes to the notebook.</figcaption></figure>



<p>Then click on the left in the main branch button, from there we will be commiting the changes to our repository:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="314" src="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD6-1024x314.png" alt="" class="wp-image-1424" srcset="https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD6-1024x314.png 1024w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD6-300x92.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD6-768x235.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD6-1536x470.png 1536w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD6-2048x627.png 2048w, https://www.albertnogues.com/wp-content/uploads/2022/04/DatabricksCICD6-196x60.png 196w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Fig 6. Pushing our notebook to the DevOps repo</figcaption></figure>



<p>If we go back now to our Azure DevOps project we should see the file has been commited to the repository. This ends the first part of this tutorial.</p>



<p>In the second blog entry we will see how to trigger the pipeline after a modification of this notebook and passing the credentials of the second workspace to be able to deliver the changed notebook to our Production (target) workspace.</p>
<p>The post <a href="https://www.albertnogues.com/implementing-ci-cd-in-databricks-with-azure-devops-part-1/">Implementing CI/CD in Databricks with Azure DevOps (Part 1)</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Databricks cluster policies at a glance. The easy way!</title>
		<link>https://www.albertnogues.com/databricks-cluster-policies-at-a-glance-the-easy-way/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=databricks-cluster-policies-at-a-glance-the-easy-way</link>
		
		<dc:creator><![CDATA[Albert]]></dc:creator>
		<pubDate>Tue, 08 Feb 2022 17:30:00 +0000</pubDate>
				<category><![CDATA[Databricks]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[databricks]]></category>
		<category><![CDATA[spark]]></category>
		<guid isPermaLink="false">https://www.albertnogues.com/?p=1318</guid>

					<description><![CDATA[<p>For these administering one or more databricks workspaces, cluster policies are an important tool where we spend some time with. Introduction But what are cluster policies? Cluster policies are basically a json file with some parameters that we use to allow (or not) users to select certain things when creating a cluster. Not only users &#8230; </p>
<p>The post <a href="https://www.albertnogues.com/databricks-cluster-policies-at-a-glance-the-easy-way/">Databricks cluster policies at a glance. The easy way!</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>For these administering one or more databricks workspaces, cluster policies are an important tool where we spend some time with.</p>



<h2 class="wp-block-heading" id="introduction">Introduction</h2>



<p>But what are cluster policies?</p>



<p>Cluster policies are basically a json file with some parameters that we use to allow (or not) users to select certain things when creating a cluster. Not only users select (or deselect) but we can force some parameters of the cluster as well by default.</p>



<p>The purpose of using cluster policies is not only standarizing of forcing certain specific configurations but also to limit human error that can cost the copany lots of money by capping certain parameters to only allow specific machine sizes, maximum number of nodes, or the cluster timeout.</p>



<p>To be able to use cluster policies, you need to have a Premium workspace. And of course, be an admin of the workspace to be able to define them.</p>



<h3 class="wp-block-heading" id="format-of-a-cluster-policy-and-it-s-elements">Format of a cluster policy and it&#8217;s elements</h3>



<p>The format of a policy, as we said, its a json document:</p>



<pre class="wp-block-code"><code>interface Policy {
  &#91;path: string]: PolicyElement
}</code></pre>



<p>The type of policy elements we can use to control its quite long, and you have them explained in the official databricks documentation:</p>



<ul class="wp-block-list"><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#fixed-policy">Fixed policy</a></li><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#forbidden-policy">Forbidden policy</a></li><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#limiting-policies-common-fields">Limiting policies: common fields</a></li><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#allow-list-policy">Allow list policy</a></li><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#block-list-policy">Block list policy</a></li><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#regex-policy">Regex policy</a></li><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#range-policy">Range policy</a></li><li><a href="https://docs.databricks.com/administration-guide/clusters/policies.html#unlimited-policy">Unlimited policy</a></li></ul>



<p>In this article, we will create a simple policy, that will preconfigure a cluster based on a specific machine size, we will restrict the maximum number of nodes to 5, and that will autotag the cluster with a specific key that we will define in the policy.</p>



<p>However there are endless possibilities so I recommend you to have a look at the official documentation to have yourself an idea of all the parameters you can configure <a href="https://docs.databricks.com/administration-guide/clusters/policies.html" target="_blank" rel="noreferrer noopener">here</a>.</p>



<h2 class="wp-block-heading" id="creating-a-custom-cluster-policy">Creating a custom cluster policy</h2>



<p>Ok, lets start! To create our first policy we need to log in into our workspace, go to the compute section and click on the cluster policies tab:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="980" height="586" src="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies1.png" alt="" class="wp-image-1321" srcset="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies1.png 980w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies1-300x179.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies1-768x459.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies1-100x60.png 100w" sizes="auto, (max-width: 980px) 100vw, 980px" /><figcaption>Fig 1. Creating a Cluster Policy on Azure Databricks</figcaption></figure>



<p>Then, there if we have rights (i.e. we are administrators of the workspace) we should see a buton called Create Cluster Policy. Once clicked we will see something similar to Fig 2:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="673" height="505" src="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies2.png" alt="" class="wp-image-1322" srcset="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies2.png 673w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies2-300x225.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies2-80x60.png 80w" sizes="auto, (max-width: 673px) 100vw, 673px" /><figcaption>Fig 2. A Cluster Policy</figcaption></figure>



<p>Here we have to concentrate on three things. The first one, is the policy name. This is the name your users will see, so I recommend to choose a meaningful name. For example multinode small cluster, or something like that.</p>



<p>Once the name is selected, we need to actually define the policy. This is a json area content box. In my sample case i want a to create a policy that chooses by default a machine with a small/medium size sku and maximum can autoscale to 5 nodes. Also i want to tag the cluster with a fixed string. To go further on this example, i will give the user a choice of two machines for the nodes, while the driver will be restricted to a specific vm sku. I will also set up auto termination to 10 minutes to make sure i am not paying for something not in use. My policy will look like the following:</p>



<pre class="wp-block-code"><code>{
  "node_type_id": {
    "type": "allowlist",
    "values": &#91;
      "Standard_D8d_v4",
      "Standard_D16d_v4"
    ],
    "defaultValue": "Standard_D8d_v4"
  },
  "driver_node_type_id": {
    "type": "fixed",
    "value": "Standard_D8d_v4",
    "hidden": true
  },
  "autoscale.min_workers": {
    "type": "fixed",
    "value": 1,
    "hidden": true
  },
  "autoscale.max_workers": {
    "type": "range",
    "maxValue": 5,
    "defaultValue": 2
  },
  "autotermination_minutes": {
    "type": "fixed",
    "value": 10,
    "hidden": true
  },
  "custom_tags.project": {
    "type": "fixed",
    "value": "Albert"
  }
}</code></pre>



<p>Once defined i will click on save. If the format of the policy is ok, the cluster policy will be created. I can then go to the permissions tab and assign it to users or groups. By default the policy is only assigned to be used by the admin group:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="833" height="487" src="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies3.png" alt="" class="wp-image-1323" srcset="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies3.png 833w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies3-300x175.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies3-768x449.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies3-103x60.png 103w" sizes="auto, (max-width: 833px) 100vw, 833px" /><figcaption>Fig 3. Permissions for a policy</figcaption></figure>



<p>We will leave it as it is as we are just playing arround.</p>



<p>We can now try to create a cluster using this policy:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1003" height="937" src="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies4.png" alt="" class="wp-image-1325" srcset="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies4.png 1003w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies4-300x280.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies4-768x717.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies4-64x60.png 64w" sizes="auto, (max-width: 1003px) 100vw, 1003px" /><figcaption>Fig 4. Create a cluster with the new policy</figcaption></figure>



<p>Select the newly created policy, then in the worker type by default in the policy we are choosing the machine sku Dtandard_D8d_v4 but we are allowing the user to chose a bigger one, and in the autoscaling we can choose up to 5 nodes. If we try to input 6 we will get an error: &#8220;Max Workers cannot be more than 5&#8221; and will not let us go through the cluster creation.</p>



<p>The driver type and the default cluster timeout are not seen as we dont allow the user to change it, they are set by default and we choose to mak them hidden. By removing the hidden attribute we will let the users to see the values but not modifying it:</p>



<pre class="wp-block-code"><code>"driver_node_type_id": {
    "type": "fixed",
    "value": "Standard_D8d_v4",
    <strong>"hidden": true</strong>
  },
...
  "autotermination_minutes": {
    "type": "fixed",
    "value": 10,
    <strong>"hidden": true</strong>
  },</code></pre>



<p>And the last needed to be check is in the advanced options. We wanted to autotag the cluster with the project tag with a set string. If we uncollapse the advanced options we can verify how this tag is applied:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="790" height="606" src="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies5.png" alt="" class="wp-image-1326" srcset="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies5.png 790w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies5-300x230.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies5-768x589.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies5-78x60.png 78w" sizes="auto, (max-width: 790px) 100vw, 790px" /><figcaption>Fig 5. Project tag in advanced options</figcaption></figure>



<p>And if we go to our cloud provider and we check the machines created as part of the cluster we will see how the tag has also been propagated to the cloud resources. This will allow us to do cost analysis from the provider cloud portal.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="305" src="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies6-1024x305.png" alt="" class="wp-image-1328" srcset="https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies6-1024x305.png 1024w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies6-300x89.png 300w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies6-768x229.png 768w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies6-1536x458.png 1536w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies6-2048x610.png 2048w, https://www.albertnogues.com/wp-content/uploads/2022/02/ClusterPolicies6-201x60.png 201w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Fig 6. Project Tag propagated to the underlying cloud resource (VM).</figcaption></figure>



<h2 class="wp-block-heading" id="next-steps">Next Steps</h2>



<p>There is also another very good article about defining the strategy when implementing policies. As this process can lead to some errors its important not to enforce the policies directly in a production workspace before testing. Databricks has created a reference methodology that i think it makes perfect sense when implementing these policies, starting by testing the policy, then create a barebone policy to do some tagging, then deploy the real policy but without enforcing it to any user (so it can only be selected optionally) and once tested everything is working as expected then enforce it to the users.</p>



<p>By using this framework you can simply correct all aspects that may be wrong before creating a potential issue to the final users.</p>



<p>There is also an interesting section in that article which is a worry usually for all of us that work for large user base. This is the tag enforcement of resources, very important when crosscharging between teams or different parts of the organization is required. In order to be able to input the costs to the proper project, department or other body, you need to enforce tagging of your resources. This is a very important topic when working on the cloud and while its a bit difficult to implement a proper tagging policy in databricks as you have mainly to rely on freeform text or some regex expression, you can try to build an effective system to crosscharge your projects or departments in the use of your databricks workspace(s).</p>



<p>This set of best practices and challenges is documented <a href="https://docs.databricks.com/administration-guide/clusters/policies-best-practices.html" target="_blank" rel="noreferrer noopener">here</a> and for me its an important resource for any databricks administrator.</p>



<p>Have fun!</p>
<p>The post <a href="https://www.albertnogues.com/databricks-cluster-policies-at-a-glance-the-easy-way/">Databricks cluster policies at a glance. The easy way!</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Using Azure Private Endpoints with Databricks</title>
		<link>https://www.albertnogues.com/using-azure-private-endpoints-with-databricks/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=using-azure-private-endpoints-with-databricks</link>
		
		<dc:creator><![CDATA[Albert]]></dc:creator>
		<pubDate>Thu, 09 Dec 2021 19:31:32 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Databricks]]></category>
		<category><![CDATA[Spark]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[databricks]]></category>
		<category><![CDATA[PrivateEndpoints]]></category>
		<category><![CDATA[spark]]></category>
		<guid isPermaLink="false">https://www.albertnogues.com/?p=1235</guid>

					<description><![CDATA[<p>In this article i will show how to avoing going outside to the internet when using resources inside azure, specially if they are in the same subscription and location (datacenter). Why we may want a private endpoint? Thats a good question. For oth security and performance. Just like using TSCM Equipment for optimal safety and &#8230; </p>
<p>The post <a href="https://www.albertnogues.com/using-azure-private-endpoints-with-databricks/">Using Azure Private Endpoints with Databricks</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this article i will show how to avoing going outside to the internet when using resources inside azure, specially if they are in the same subscription and location (datacenter).</p>



<p>Why we may want a private endpoint? Thats a good question. For oth security and performance. Just like using <a href="https://spyassociates.com/counter-surveillance">TSCM Equipment</a> for optimal safety and security. We dont want the traffic going outside to the internet to return again back to the azure datacenter if the resource we are trying to reach is already there. So with a PrivateLink the traffic will stay inside the Azure backbone network avoiding reaching the internet. More information about private endpoints <a href="https://azure.microsoft.com/en-us/services/private-link/" target="_blank" rel="noreferrer noopener">here</a> and <a href="https://docs.microsoft.com/en-us/azure/private-link/private-link-overview" target="_blank" rel="noreferrer noopener">here</a>.</p>



<p>Though its possible to create private endpoints to connect to services in other subcriptions we will use the same subscription and the West Europe Region in this article. The goal is to connect to both a AzureSQL database using private connectivity and to a datalake using private connectivity as well.</p>



<h2 class="wp-block-heading">Creating a Private Endpoint for AzureSQL and integrating in the databricks vnet</h2>



<p>For this, i created a Databricks workspace and selected to use an already existing VNET, so this way I can add a new subnet for my private endpoints. One of the good things of doing this way is that NICs between subnets see each other and are reacheable (unless we block it with a network security group) but by default traffic is open within the VNET. So I can create a Private endpoint in a specific subnet of the same VNET that hosts the databricks subnets.</p>



<p>Bear in mind that it&#8217;s not possible to add a private endpoint to a subnet managed by databricks. So the two subnets we created, when we deployed the databricks workspace (Bot public and private) should not be modified. We will create a new one as shown in the screen below:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="145" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep4-1024x145.png" alt="" class="wp-image-1236" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep4-1024x145.png 1024w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep4-300x43.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep4-768x109.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep4-1536x218.png 1536w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep4-2048x290.png 2048w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep4-424x60.png 424w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Our  Databricks VNET. Among the two subnets created when the databricks workspace is created i added a new one to host our Private Endpoints</figcaption></figure>



<p>Once defined properly the VNET, we are going to create the private endpoint to reach our AzureSQL through it.</p>



<p>First we need to go to the Azure Portal, find our AzureSQL Server, and click on the left menu called Private Endpoint Connections and click on the plus sing on top to create a new one. We just need to select the subscription, the resource group the nameof the private endpoint and the region. We can fill it as shown in the following picture:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="946" height="626" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep1.png" alt="" class="wp-image-1237" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep1.png 946w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep1-300x199.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep1-768x508.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep1-91x60.png 91w" sizes="auto, (max-width: 946px) 100vw, 946px" /><figcaption class="wp-element-caption">Private Endpoint Creation. Step 1</figcaption></figure>



<p>The second step requires a bit more of information, here we will define which resource we try to target with our private endpoint. As expected we need to find our AzureSQL Server here. We fill the combo boxes as usual</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="920" height="529" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep2.png" alt="" class="wp-image-1238" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep2.png 920w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep2-300x173.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep2-768x442.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep2-330x190.png 330w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep2-104x60.png 104w" sizes="auto, (max-width: 920px) 100vw, 920px" /><figcaption class="wp-element-caption">Private Endpoint Creation. Step 2</figcaption></figure>



<p>The third screen is the most important one. We need to select the VNET and Subnets that will host our private endpoint. In this case we want to use databricks so we need to use the VNET we created for databrickks, and then the subnet we created specifically to host the private endpoints.</p>



<p>Another important step here is to integrate it with the DNS. If we dont integrate it, when we use the AzureSQL hostname provided by azure we will still access through the public endpoint. By integrating it in the DNS. the dns queries over the public endpoint in this private zone, will resolve to the private IP of the NIC of the Private Endpoint</p>



<p>If we chose no for the DNS integration then we will have to add static entries in the /etc/hosts or somewhat, or use the private IP instead of the hostname when connecting to the AzureSQL server. To simplify we choose to integrate it.</p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="583" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep3-1024x583.png" alt="" class="wp-image-1239" style="width:840px;height:478px" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep3-1024x583.png 1024w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep3-300x171.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep3-768x438.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep3-105x60.png 105w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep3.png 1241w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption"> Private Endpoint Creation. Step 3.</figcaption></figure>



<p>Once created we should see the private endpoint available. If you look at the right its implemented though a NIC (Network Interface card), and by clicking on it, we can find it and see the ip address assigned:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="177" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep5-1024x177.png" alt="" class="wp-image-1241" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep5-1024x177.png 1024w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep5-300x52.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep5-768x132.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep5-1536x265.png 1536w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep5-2048x353.png 2048w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep5-348x60.png 348w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Our newly created Private Endpoint for Azure SQL</figcaption></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="225" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep6-1024x225.png" alt="" class="wp-image-1242" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep6-1024x225.png 1024w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep6-300x66.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep6-768x168.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep6-1536x337.png 1536w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep6-2048x449.png 2048w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep6-274x60.png 274w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Finding the PrivateIP Address of the NIC that implements the private endpoint</figcaption></figure>



<h2 class="wp-block-heading">Test the AzureSQL DB Endpoint from Databricks</h2>



<p>Now we have it ready. We can still see from outside that VNET, that our old server still resolves to a public ip, as it was the case before even inside databricks. We can ping it for testing purposes:</p>



<pre class="wp-block-code"><code>C:\Users\Albert&gt;ping azure-sql-server-albert.database.windows.net

Haciendo ping a cr4.westeurope1-a.control.database.windows.net &#91;<strong>104.40.168.105</strong>] con 32 bytes de datos:</code></pre>



<p>As you can see we have a public ip, but lets try to ping it inside the cluster:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="885" height="178" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep7.png" alt="" class="wp-image-1244" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep7.png 885w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep7-300x60.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep7-768x154.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep7-298x60.png 298w" sizes="auto, (max-width: 885px) 100vw, 885px" /><figcaption class="wp-element-caption">Private endpoint with the DNS integration working fine. Our dns record for the AzureSQL Db does not resolve to a public ip anymore but to the private IP of the PrivateEndpoint</figcaption></figure>



<p>So it&#8217;s working. Its using the private ip instead of the public one. Our last step is to see if we can fetch the data from the database:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="363" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep8-1024x363.png" alt="" class="wp-image-1245" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep8-1024x363.png 1024w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep8-300x106.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep8-768x272.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep8-1536x544.png 1536w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep8-2048x726.png 2048w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep8-169x60.png 169w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Accessing AzureSQL Database though a private endpoint from databricks</figcaption></figure>



<h2 class="wp-block-heading">Creating an AzureDataLake PrivateEndpoint and saving our data to the DataLake through it.</h2>



<p>We are not done yet! We can still complicate matters and create a private endpoint as well to save data to our datalake.</p>



<p>I&#8217;ve created an ADLS Gen 2 storage account, and going back to databricks I see by default it&#8217;s using public access:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="836" height="194" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep9.png" alt="" class="wp-image-1246" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep9.png 836w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep9-300x70.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep9-768x178.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep9-259x60.png 259w" sizes="auto, (max-width: 836px) 100vw, 836px" /><figcaption class="wp-element-caption">Datalake public access</figcaption></figure>



<p>But we can implement a Private Endpoint as well, and route all the traffic through the azure datacenter itself. Lets see how to do it. For achieving this, we go to our ADS Gen2 storage account, and on the left we click again in Networking, and the second tab is called Private Endpoint connections. We click the plus button to create a new one, and basically we follow the same steps as before with a subtle difference</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="930" height="760" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep10.png" alt="" class="wp-image-1247" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep10.png 930w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep10-300x245.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep10-768x628.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep10-73x60.png 73w" sizes="auto, (max-width: 930px) 100vw, 930px" /><figcaption class="wp-element-caption">Creation of a private endpoint for an ADLS Gen2 storage account.</figcaption></figure>



<p>The difference with a storage account is that we need to chose which api we want to create the private endpoint for. We can use the blob, the table, the queue, the file share and the dfs (DataLake) endpoint (And also the static website!).</p>



<p>We will use the dfs endpoint, and again we will place it in the Private Endpoint subnet of our Databricks vnet. Something like this:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="814" height="990" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep11.png" alt="" class="wp-image-1248" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep11.png 814w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep11-247x300.png 247w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep11-768x934.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep11-49x60.png 49w" sizes="auto, (max-width: 814px) 100vw, 814px" /><figcaption class="wp-element-caption">Creating a Private Endpoint for our DataLake an dplacing it in the appropiate subnet</figcaption></figure>



<p>After a few minutes our private endpoint will be ready to be used. We can go again to see the NIC and check the private ip or go directly to databricks and ping the storage account url to see if now it&#8217;s resolving to our private endpoint:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="796" height="184" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep12.png" alt="" class="wp-image-1249" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep12.png 796w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep12-300x69.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep12-768x178.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep12-260x60.png 260w" sizes="auto, (max-width: 796px) 100vw, 796px" /><figcaption class="wp-element-caption">As we can see now databricks resolves our storage account through the private endpoint</figcaption></figure>



<h2 class="wp-block-heading">Test the ADLS Gen2 SA endpoint from Databricks </h2>



<p>If we have the IAM credential Passthrough enabled in our cluster and we have permisison to write to the datalake, now we should be able to write there without going through the internet:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="175" src="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep13-1024x175.png" alt="" class="wp-image-1250" srcset="https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep13-1024x175.png 1024w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep13-300x51.png 300w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep13-768x132.png 768w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep13-1536x263.png 1536w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep13-2048x351.png 2048w, https://www.albertnogues.com/wp-content/uploads/2021/12/SQlPep13-350x60.png 350w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Writing to a DataLake through the Private Endpoint we just created</figcaption></figure>



<p>So this is the end of the tutorial. We created two private endpoints, one for AzureSQL Database and Another for our DataLake and used bot them from Databricks. We also confirmed we are effectively using them by pinging the hostnames of both resources and seeing a change from the public ip to the private one.</p>



<p>Happy Data pojects!</p>
<p>The post <a href="https://www.albertnogues.com/using-azure-private-endpoints-with-databricks/">Using Azure Private Endpoints with Databricks</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Use Redshift Spectrum to query infrequently used data on S3</title>
		<link>https://www.albertnogues.com/use-redshift-spectrum-to-query-infrequently-used-data-on-s3/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=use-redshift-spectrum-to-query-infrequently-used-data-on-s3</link>
		
		<dc:creator><![CDATA[Albert]]></dc:creator>
		<pubDate>Wed, 30 Dec 2020 11:14:01 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[BigData]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[datawarehousing]]></category>
		<category><![CDATA[redshift]]></category>
		<category><![CDATA[spectrum]]></category>
		<guid isPermaLink="false">http://192.168.1.40/?p=994</guid>

					<description><![CDATA[<p>Redshift spectrum lets us to query data in s3 buckets using redshift. This scenario is specially interesting in large datawarehouses with data that we do not need to query often but it may be nevessary from time to time to run some of our queries. In this situation, probably we dont want the data to &#8230; </p>
<p>The post <a href="https://www.albertnogues.com/use-redshift-spectrum-to-query-infrequently-used-data-on-s3/">Use Redshift Spectrum to query infrequently used data on S3</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Redshift spectrum lets us to query data in s3 buckets using redshift. This scenario is specially interesting in large datawarehouses with data that we do not need to query often but it may be nevessary from time to time to run some of our queries. In this situation, probably we dont want the data to be loaded into our redshift cluster as this may push us to provision larger redshift clusters that the ones we need for procession our usual queries (take into account that redshift clusters are set with specific cpu, ram and space and they can not be totally tailored to our needs, so only few combinations are available)</p>



<p>There are a few requirements however to be able to use redshift spectrum. First, the data loaded will be like an external table in other systems (RDBMS) or like hive external tables. So this means that we can forget about updating or deleting our data. We will only get read only capability, but usually thats we are looking for (think in historical data from already closed exercices, archived data and so on), where the cost of storing it in s3 even in a cool tier can ve several orders of magnitude cheaper than keeping it inside redshift.</p>



<p>There are other technical limitations tough. For example, <strong>the s3 bucket has to be in the same region as our redshift cluster</strong>, so plan in advance or move the data to another s3 bucket. There are other requirements like permissions and so on, you can read it <a rel="noreferrer noopener" href="https://docs.aws.amazon.com/redshift/latest/dg/c-using-spectrum.html" data-type="URL" data-id="https://docs.aws.amazon.com/redshift/latest/dg/c-using-spectrum.html" target="_blank">here</a>.</p>



<p>Before starting we need to attach a role to our redshift cluster that grants access to read s3 buckets. If you followed my previous article on redshift you will already have this role, otherwise check how to do it <a href="https://www.albertnogues.com/load-data-from-s3-and-run-tpc-ds-queries-on-amazon-redshift/" data-type="URL" data-id="https://www.albertnogues.com/load-data-from-s3-and-run-tpc-ds-queries-on-amazon-redshift/">here</a>.</p>



<p>If you followed my previous article, apart of the s3 read only permisison, you need to add the glue catalog permission to create a table. For this, modify the role (or if you&#8217;re creating a new one, add the following permission: <code>AWSGlueConsoleFullAccess</code></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="633" src="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum0-1024x633.png" alt="" class="wp-image-997" srcset="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum0-1024x633.png 1024w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum0-300x185.png 300w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum0-768x475.png 768w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum0-97x60.png 97w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum0.png 1031w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>For the sake of this exercise I&#8217;ve load part of the TPC-DS customer data into a s3 bucket i made public on the Paris region. Then we will create an external customer table pointing to the data in the bucket (which is in fact compressed in gz) and we will query that data from redshift.</p>



<p>Once the bucket data is loaded, we are ready to go back to our redshift cluster. I&#8217;ve used <a href="https://redshift-downloads.s3.amazonaws.com/TPC-DS/2.13/3TB/customer/customer_1_14.dat.gz" data-type="URL" data-id="https://redshift-downloads.s3.amazonaws.com/TPC-DS/2.13/3TB/customer/customer_1_14.dat.gz" target="_blank" rel="noreferrer noopener">this file</a> for the tests. We will create an external schema and an external customers table. For this we need first to copy the arn of the role we created with the s3 read access. To get that let&#8217;s go to our cluster, then click on properties and later on click in Copy Amazon Resource Name (ARN):</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="383" src="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum1-1024x383.png" alt="" class="wp-image-996" srcset="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum1-1024x383.png 1024w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum1-300x112.png 300w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum1-768x287.png 768w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum1-1536x574.png 1536w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum1-161x60.png 161w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum1.png 1787w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>Once we have the arn of our role, then run the folloowing in your editor. It will create the external schema in a new spectrum database (feel free to choose any other database name if you need)</p>



<pre class="wp-block-code"><code>create external schema spectrum_albertnogues 
from data catalog 
database 'spectrum' 
iam_role 'arn:aws:iam::742123541312:role/Redshift_Albertnogues.com'
create external database if not exists;</code></pre>



<p>Then we are ready to create our external table:</p>



<pre class="wp-block-code"><code>create external table spectrum_albertnogues.customer
(
  c_customer_sk int4,                 
  c_customer_id char(16),             
  c_current_cdemo_sk int4 ,   
  c_current_hdemo_sk int4 ,   
  c_current_addr_sk int4 ,    
  c_first_shipto_date_sk int4 ,                 
  c_first_sales_date_sk int4 ,
  c_salutation char(10) ,     
  c_first_name char(20) ,     
  c_last_name char(30) ,      
  c_preferred_cust_flag char(1) ,               
  c_birth_day int4 ,          
  c_birth_month int4 ,        
  c_birth_year int4 ,         
  c_birth_country varchar(20) ,                 
  c_login char(13) ,          
  c_email_address char(50) ,  
  c_last_review_date_sk int4
)
row format delimited
fields terminated by '|'
stored as textfile
location 's3://redshift-spectrum-albertnogues/customers/';</code></pre>



<p>As you can see it&#8217;s not really 100% the same customers table from the TPC-DS data. This is because external tables do not support primary keys, not null syntax and some other keywords that do not make sense in external tables. Make sure you used the right separator and selected the right format of data (compression is determined by the file extension).</p>



<p>Then, as you will see the table creation takes virtually nothing. This is because in fact, the data is not loaded, its only a shortcut to our s3 data. But to make sure it&#8217;s working we can run a few queries to our new table:</p>



<pre class="wp-block-code"><code>select count(*) from spectrum_albertnogues.customer;</code></pre>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="448" height="163" src="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum2.png" alt="" class="wp-image-998" srcset="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum2.png 448w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum2-300x109.png 300w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum2-165x60.png 165w" sizes="auto, (max-width: 448px) 100vw, 448px" /></figure>



<p>And to make sure data is properly loaded, we can query it as well:</p>



<pre class="wp-block-code"><code>select * from spectrum_albertnogues.customer LIMIT 5;</code></pre>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="189" src="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum3-1024x189.png" alt="" class="wp-image-999" srcset="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum3-1024x189.png 1024w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum3-300x55.png 300w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum3-768x142.png 768w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum3-324x60.png 324w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum3.png 1238w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>As a last example, if you run my previous blog post on redshift, we can now join our new external customers table with our web returns fact table, to see how many objects these users returned depending on their origin country, to see if there is any pattern or not.</p>



<pre class="wp-block-code"><code>select c_birth_country as customer_birth_country, sum(wr_return_quantity) as qty_returned_total
 from web_returns,
      date_dim,
     spectrum_albertnogues.customer
 where wr_returned_date_sk = d_date_sk 
   and d_year =2002
   and wr_returning_customer_sk = c_customer_sk
 group by c_birth_country
 order by 2 desc;</code></pre>



<p>Of course the query should take a bit more since the data is not inside redshift, and needs to be fetched from s3 but we can get our output quite fast and easily:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="709" height="547" src="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum4.png" alt="" class="wp-image-1000" srcset="https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum4.png 709w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum4-300x231.png 300w, https://www.albertnogues.com/wp-content/uploads/2020/12/Spectrum4-78x60.png 78w" sizes="auto, (max-width: 709px) 100vw, 709px" /></figure>



<p>Thats it!. For more advanced topics like performance improvements when querying from s3 and others, you can read <a rel="noreferrer noopener" href="https://docs.aws.amazon.com/redshift/latest/dg/c-spectrum-external-performance.html" data-type="URL" data-id="https://docs.aws.amazon.com/redshift/latest/dg/c-spectrum-external-performance.html" target="_blank">here</a> and <a href="https://blog.openbridge.com/10-simple-tips-that-help-you-quickly-find-success-adopting-amazon-redshift-spectrum-810db089abbe" data-type="URL" data-id="https://blog.openbridge.com/10-simple-tips-that-help-you-quickly-find-success-adopting-amazon-redshift-spectrum-810db089abbe" target="_blank" rel="noreferrer noopener">here</a>. I recommend basically partitioning, a splittable file format like parquet compressed with snappy or some other codec, small files (but not very small), add as many filers as you can to avoid retrieving unnecesary data, and if you use a columnar format like parquet, you will avoid fetching unused columns in your select statement. This is important (and can have a huge impact in costs) because now it&#8217;s the time of discussing the price of all this.</p>



<p>Bear in mind that <strong>AWS charges 5 dollars for each Terabyte of data scanned from s3 with spectrum</strong>, so make sure you do the right usage on this (only data infrequently queried) and do not overestimate these charges as they grew quickly.</p>



<p>For expert advice or project requests you can contact me <a rel="noreferrer noopener" href="https://www.albertnogues.com/contact/" data-type="URL" data-id="https://www.albertnogues.com/contact/" target="_blank">here</a>. Happy Querying!</p>
<p>The post <a href="https://www.albertnogues.com/use-redshift-spectrum-to-query-infrequently-used-data-on-s3/">Use Redshift Spectrum to query infrequently used data on S3</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Deploying an Azure Storage Account with a queue with terraform and python</title>
		<link>https://www.albertnogues.com/deploying-and-interacting-with-an-azure-storage-account-and-a-queue-with-terraform-and-python-part-i/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=deploying-and-interacting-with-an-azure-storage-account-and-a-queue-with-terraform-and-python-part-i</link>
		
		<dc:creator><![CDATA[Albert]]></dc:creator>
		<pubDate>Wed, 23 Dec 2020 14:39:14 +0000</pubDate>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[Queue]]></category>
		<category><![CDATA[Storage Account]]></category>
		<category><![CDATA[Terraform]]></category>
		<guid isPermaLink="false">http://192.168.1.40/?p=939</guid>

					<description><![CDATA[<p>In this post we will deploy the azure infrastructure to have an storage account queue. For this we will use terraform which can be downloaded from here. Before start, we need a few prerequisites, these are the following: Installing terraform, azure-cli and azure-storage-queue Create a service principal for deploying the resources with terraform Creating the &#8230; </p>
<p>The post <a href="https://www.albertnogues.com/deploying-and-interacting-with-an-azure-storage-account-and-a-queue-with-terraform-and-python-part-i/">Deploying an Azure Storage Account with a queue with terraform and python</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this post we will deploy the azure infrastructure to have an storage account queue. For this we will use terraform which can be downloaded from <a rel="noreferrer noopener" href="https://www.terraform.io/downloads.html" target="_blank">here</a>.</p>



<p>Before start, we need a few prerequisites, these are the following:</p>



<ol class="wp-block-list"><li>Installing terraform, azure-cli and azure-storage-queue</li><li>Create a service principal for deploying the resources with terraform</li><li>Creating the terraform tf file with all the components required to be deployed. These include:<ul><li>A Resource Group</li><li>A Storage account</li><li>A queue inside the previous storage account</li></ul></li><li>Run the terraform deployment</li><li>Write the python code to send a message and retrieve it from the queue created in the storage account (Part II)</li></ol>



<p>Let&#8217;s start!</p>



<p>Before starting to work with terraform, we need to install terraform. We can do it easily downloading it from the official website and placing it in the path of our sysvars. We can download the latest packaged binary from <a rel="noreferrer noopener" href="https://www.terraform.io/downloads.html" target="_blank">here</a>.</p>



<p>To install azure-cli and azure-storage-queue we can use python + pip. If you dont have python, you can download it from the official website <a rel="noreferrer noopener" href="https://www.python.org/downloads/" target="_blank">here</a>. Make suire you install pip as well as part of the installation process.</p>



<p>Once python is setup we can run the following to install the packages and it&#8217;s dependencies:</p>



<pre class="wp-block-code"><code>pip install azure-cli azure-queue-storage</code></pre>



<p>After installing the packages we are good to start moving to point 2. For the service principal creation we can use the recently installed azure-cli. The call to create the spn is as follows:</p>



<pre class="wp-block-code"><code>az ad sp create-for-rbac --name="<strong><span class="has-inline-color has-vivid-red-color">SPForTerraform</span></strong>" --role="Contributor" --scopes="/subscriptions/<strong><span class="has-inline-color has-vivid-red-color">ourSubscriptionId</span></strong>"</code></pre>



<p>Make sure you replace ourSubscriptionId by your azure subscription. In case you dont know where to obtain it you can follow the following <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/azure/media-services/latest/how-to-set-azure-subscription?tabs=portal" data-type="URL" data-id="https://docs.microsoft.com/en-us/azure/media-services/latest/how-to-set-azure-subscription?tabs=portal" target="_blank">procedure</a> or <a href="https://docs.bitnami.com/azure/faq/administration/find-subscription-id/" data-type="URL" data-id="https://docs.bitnami.com/azure/faq/administration/find-subscription-id/" target="_blank" rel="noreferrer noopener">this one</a>. The spn we will create will be named with the &#8211;name parameter and will have the contributor role. This means this spn will have access to everything but to manage users. So we can create any sort of resouce with in. This process may take a few seconds, after a while we should see something like this:</p>



<pre class="wp-block-code"><code>Changing "SPForTerraform" to a valid URI of "http://SPForTerraform", which is the required format used for service principal names
Creating a role assignment under the scope of "/subscriptions/xxxxxx"
  Retrying role assignment creation: 1/36
  Retrying role assignment creation: 2/36
  Retrying role assignment creation: 3/36
The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
{
  "appId": "xxxxxx",
  "displayName": "SPForTerraform",
  "name": "http://SPForTerraform",
  "password": "yyyyyy",
  "tenant": "zzzzzz"
}</code></pre>



<p>Make sure you protect these, as anybody getting them will be able to access your tenant and start deploying resources in it.</p>



<p>Now, we can move to the thid point which is creating the terraform file. We can start now our preferred editor and create a *.tf file with the following content:</p>



<pre class="wp-block-code"><code>provider "azurerm" {
subscription_id = "kkkkkk"
client_id = "xxxxxx"
client_secret = "yyyyyy"
tenant_id = "zzzzzz"
features {}
}

terraform {
  required_version = "&gt;= 0.13"
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
    }
  }
} </code></pre>



<p>The first block initializes the provider azurerm from terraform, while the second one initializes the terraform file with the required azurerm providrer, and tells terraform where to obtain it and which is the minimum version required. client_id is the same as the appID returned by the az cli when the spn was created.</p>



<p>Then we need another three blocks, one for each resource we want to deploy:</p>



<pre class="wp-block-code"><code>resource "azurerm_resource_group" "rg1" {
name = "TerraformRG"
location = "West Europe"
tags = { Owner = "Albert Nogues" }
}

resource "azurerm_storage_account" "sacc1" {
  name                     = "teststorageacc1"
  resource_group_name      = azurerm_resource_group.rg1.name
  location                 = azurerm_resource_group.rg1.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

resource "azurerm_storage_queue" "queue1" {
  name                 = "queue1"
  storage_account_name = azurerm_storage_account.sacc1.name
}</code></pre>



<p>The way terraform blocks work is the following:</p>



<p>resource &#8220;name_of_the_azurerm_resource&#8221; &#8220;our_alias&#8221;{</p>



<p>&#8230; parameters and vars&#8230;</p>



<p>}</p>



<p>We can use then the alias to select things from other blocks we defined previously. So for example, in our example, the storage account, takes the location from the location field defined in the resource group, this way we ensure we create the storage accoun in the same azure location than the resource group (even it&#8217;s not mandatory). An example of how to define an storage account can be found in the official documentation <a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue" data-type="URL" data-id="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/storage_queue" target="_blank" rel="noreferrer noopener">here</a>.</p>



<p>The same with the queue, which is created in the storage_account_name referred by the previous block. We can also put tags to the resources as shown in the resource group block.</p>



<p>Once we are ready, we can launch terraform to create our resources. For security purposes (and if working in multiple environments) it&#8217;s usually not good having in the code the client_id, secret_id, tenant_id and subcription_id. Terraform can read system variables in execution time. These can be set (windows) or exported (linux) with these names:</p>



<pre class="wp-block-code"><code>ARM_SUBSCRIPTION_ID
ARM_CLIENT_ID
ARM_CLIENT_SECRET
ARM_TENANT_ID</code></pre>



<p>Once all ready we can trigger our creation script. We can navigate where our .tf form is and launch it:</p>



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



<p>Which will give us the changes needed in our azure subscription to acommodate the resources, and it should show us three changes: one for the resource group, another for the storage account and another for the queue:</p>



<pre class="wp-block-code"><code>terraform.exe plan

azurerm_resource_group.rg: Refreshing state... &#91;id=/subscriptions/kkkkkk/resourceGroups/TerraformRG]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_resource_group.rg1 will be created
  + resource "azurerm_resource_group" "rg1" {
      + id       = (known after apply)
      + location = "westeurope"
      + name     = "TerraformRG"
      + tags     = {
          + "Owner" = "Albert Nogues"
        }
    }

  # azurerm_storage_account.sacc1 will be created
  + resource "azurerm_storage_account" "sacc1" {
      + access_tier                      = (known after apply)
      + account_kind                     = "StorageV2"
      + account_replication_type         = "LRS"
      + account_tier                     = "Standard"
      + allow_blob_public_access         = false
      + enable_https_traffic_only        = true
      + id                               = (known after apply)
      + is_hns_enabled                   = false
      + large_file_share_enabled         = (known after apply)
      + location                         = "westeurope"
      + min_tls_version                  = "TLS1_0"
      + name                             = "teststorageacc1"
      + primary_access_key               = (sensitive value)
      + primary_blob_connection_string   = (sensitive value)
      + primary_blob_endpoint            = (known after apply)
      + primary_blob_host                = (known after apply)
      + primary_connection_string        = (sensitive value)
      + primary_dfs_endpoint             = (known after apply)
      + primary_dfs_host                 = (known after apply)
      + primary_file_endpoint            = (known after apply)
      + primary_file_host                = (known after apply)
      + primary_location                 = (known after apply)
      + primary_queue_endpoint           = (known after apply)
      + primary_queue_host               = (known after apply)
      + primary_table_endpoint           = (known after apply)
      + primary_table_host               = (known after apply)
      + primary_web_endpoint             = (known after apply)
      + primary_web_host                 = (known after apply)
      + resource_group_name              = "TerraformRG"
      + secondary_access_key             = (sensitive value)
      + secondary_blob_connection_string = (sensitive value)
      + secondary_blob_endpoint          = (known after apply)
      + secondary_blob_host              = (known after apply)
      + secondary_connection_string      = (sensitive value)
      + secondary_dfs_endpoint           = (known after apply)
      + secondary_dfs_host               = (known after apply)
      + secondary_file_endpoint          = (known after apply)
      + secondary_file_host              = (known after apply)
      + secondary_location               = (known after apply)
      + secondary_queue_endpoint         = (known after apply)
      + secondary_queue_host             = (known after apply)
      + secondary_table_endpoint         = (known after apply)
      + secondary_table_host             = (known after apply)
      + secondary_web_endpoint           = (known after apply)
      + secondary_web_host               = (known after apply)

      + blob_properties {
          + cors_rule {
              + allowed_headers    = (known after apply)
              + allowed_methods    = (known after apply)
              + allowed_origins    = (known after apply)
              + exposed_headers    = (known after apply)
              + max_age_in_seconds = (known after apply)
            }

          + delete_retention_policy {
              + days = (known after apply)
            }
        }

      + identity {
          + principal_id = (known after apply)
          + tenant_id    = (known after apply)
          + type         = (known after apply)
        }

      + network_rules {
          + bypass                     = (known after apply)
          + default_action             = (known after apply)
          + ip_rules                   = (known after apply)
          + virtual_network_subnet_ids = (known after apply)
        }

      + queue_properties {
          + cors_rule {
              + allowed_headers    = (known after apply)
              + allowed_methods    = (known after apply)
              + allowed_origins    = (known after apply)
              + exposed_headers    = (known after apply)
              + max_age_in_seconds = (known after apply)
            }

          + hour_metrics {
              + enabled               = (known after apply)
              + include_apis          = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
            }

          + logging {
              + delete                = (known after apply)
              + read                  = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
              + write                 = (known after apply)
            }

          + minute_metrics {
              + enabled               = (known after apply)
              + include_apis          = (known after apply)
              + retention_policy_days = (known after apply)
              + version               = (known after apply)
            }
        }
    }

  # azurerm_storage_queue.queue1 will be created
  + resource "azurerm_storage_queue" "queue1" {
      + id                   = (known after apply)
      + name                 = "queue1"
      + storage_account_name = "teststorageacc1"
    }

<strong><span class="has-inline-color has-vivid-red-color">Plan: 3 to add, 0 to change, 0 to destroy.</span></strong>

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
</code></pre>



<p>Once we confirm this is the change we want and all is in order we can run terraform apply:</p>



<pre class="wp-block-code"><code>terraform.exe apply
...
...
...
Plan: 3 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: <strong>yes</strong></code></pre>



<p>We say yes and let&#8217;s go!</p>



<p>It may happen that there is some error, like a taken name, in this case we will get an error:</p>



<pre class="wp-block-code"><code>Error: Error creating Azure Storage Account "teststorageacc1": storage.AccountsClient#Create: Failure sending request: StatusCode=0 -- Original Error: autorest/azure: Service returned an error. Status=&lt;nil&gt; Code="StorageAccountAlreadyTaken" Message="The storage account named teststorageacc1 is already taken."

  on terraformTest.tf line 48, in resource "azurerm_storage_account" "sacc1":
  48: resource "azurerm_storage_account" "sacc1" {
</code></pre>



<p>We can fix it and rerun again, and the resources that were created already will not be modified (like in this case the resource group).</p>



<pre class="wp-block-code"><code>azurerm_storage_account.sacc1: Creating...
azurerm_storage_account.sacc1: Still creating... &#91;10s elapsed]
azurerm_storage_account.sacc1: Still creating... &#91;20s elapsed]
azurerm_storage_account.sacc1: Creation complete after 21s &#91;id=/subscriptions/kkkkkk/resourceGroups/TerraformRG/providers/Microsoft.Storage/storageAccounts/teststorageacc1anogues]
azurerm_storage_queue.queue1: Creating...
azurerm_storage_queue.queue1: Creation complete after 0s &#91;id=https://teststorageacc1anogues.queue.core.windows.net/queue1]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.</code></pre>



<p>Now we can either call the cli or browse through the azure portal to confirm that the storage account was created and the queue inside it:</p>



<pre class="wp-block-code"><code><strong>az storage account list</strong>
&#91;
  {
    "accessTier": "Hot",
    "allowBlobPublicAccess": false,
    "azureFilesIdentityBasedAuthentication": null,
    "blobRestoreStatus": null,
    "creationTime": "2020-12-23T18:30:49.007107+00:00",
    "customDomain": null,
    "enableHttpsTrafficOnly": true,
    "encryption": {
      "keySource": "Microsoft.Storage",
      "keyVaultProperties": null,
      "requireInfrastructureEncryption": null,
      "services": {
        "blob": {
          "enabled": true,
          "keyType": "Account",
          "lastEnabledTime": "2020-12-23T18:30:49.085263+00:00"
        },
        "file": {
          "enabled": true,
          "keyType": "Account",
          "lastEnabledTime": "2020-12-23T18:30:49.085263+00:00"
        },
        "queue": null,
        "table": null
      }
    },
    "failoverInProgress": null,
    "geoReplicationStats": null,
    "id": "/subscriptions/kkkkkk/resourceGroups/TerraformRG/providers/Microsoft.Storage/storageAccounts/teststorageacc1anogues",
    "identity": null,
    "isHnsEnabled": false,
    "kind": "StorageV2",
    "largeFileSharesState": null,
    "lastGeoFailoverTime": null,
    "location": "westeurope",
    "minimumTlsVersion": "TLS1_0",
    "name": "<strong><span class="has-inline-color has-vivid-red-color">teststorageacc1anogues</span></strong>",
    "networkRuleSet": {
      "bypass": "AzureServices",
      "defaultAction": "Allow",
      "ipRules": &#91;],
      "virtualNetworkRules": &#91;]
    },
    "primaryEndpoints": {
      "blob": "https://teststorageacc1anogues.blob.core.windows.net/",
      "dfs": "https://teststorageacc1anogues.dfs.core.windows.net/",
      "file": "https://teststorageacc1anogues.file.core.windows.net/",
      "internetEndpoints": null,
      "microsoftEndpoints": null,
      "queue": "https://teststorageacc1anogues.queue.core.windows.net/",
      "table": "https://teststorageacc1anogues.table.core.windows.net/",
      "web": "https://teststorageacc1anogues.z6.web.core.windows.net/"
    },
    "primaryLocation": "westeurope",
    "privateEndpointConnections": &#91;],
    "provisioningState": "Succeeded",
    "resourceGroup": "TerraformRG",
    "routingPreference": null,
    "secondaryEndpoints": null,
    "secondaryLocation": null,
    "sku": {
      "name": "Standard_LRS",
      "tier": "Standard"
    },
    "statusOfPrimary": "available",
    "statusOfSecondary": null,
    "tags": {},
    "type": "Microsoft.Storage/storageAccounts"
  }
]
</code></pre>



<p>And then confirming the storage account has been created we can check the queue inside:</p>



<pre class="wp-block-code"><code>az storage queue list --account-name teststorageacc1anogues

There are no credentials provided in your command and environment, we will query for the account key inside your storage account.
Please provide --connection-string, --account-key or --sas-token as credentials, or use `--auth-mode login` if you have required RBAC roles in your command. For more information about RBAC roles in storage, visit https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-rbac-cli.
Setting the corresponding environment variables can avoid inputting credentials in your command. Please use --help to get more information.
&#91;
  {
    "approximateMessageCount": null,
    "metadata": null,
    "name": "<strong><span class="has-inline-color has-vivid-red-color">queue1</span></strong>"
  }
]</code></pre>



<p>And we confirmed all is ready for our second part!</p>



<p>It&#8217;s time to move to azure-storage-queue python library for our 5th step. There are different ways to authenticate to the queue. Either we use the QueueServiceClient or the QueueService. the differences between both are in their official documentation <a rel="noreferrer noopener" href="https://pypi.org/project/azure-storage-queue/" data-type="URL" data-id="https://pypi.org/project/azure-storage-queue/" target="_blank">here</a>.</p>



<p>The easiest way albeit not the recommended one is to use the queue key, or even better, we can grab the connection string directly from the queue keys section. Be aware that this allows to do virtually all with that queue. So don&#8217;t lose this key, and if you do, rotate them and generate new ones.</p>



<p>Just open a new python file and to write a sync message use the following code:</p>



<pre class="wp-block-code"><code>from azure.storage.queue import QueueClient

queue = QueueClient.from_connection_string(conn_str="DefaultEndpointsProtocol=https;AccountName=teststorageacc1anogues;AccountKey=<strong><span class="has-inline-color has-vivid-red-color">xxxxxx</span></strong>;EndpointSuffix=core.windows.net", queue_name="<strong><span class="has-inline-color has-vivid-cyan-blue-color">queue1</span></strong>")

queue.send_message("Hello World!")</code></pre>



<p>This will send a Hello World message to our queue. If we print the output received we should see some debug info like the following:</p>



<pre class="wp-block-code"><code>{'id': 'a489914f-cc7e-4504-9feb-33b0efce6587', 'inserted_on': datetime.datetime(2020, 12, 24, 19, 21, 20, tzinfo=datetime.timezone.utc), 'expires_on': datetime.datetime(2020, 12, 31, 19, 21, 20, tzinfo=datetime.timezone.utc), 'dequeue_count': None, 'content': 'Hello World!', 'pop_receipt': 'AgAAAAMAAAAAAAAA727vbgja1gE=', 'next_visible_on': datetime.datetime(2020, 12, 24, 19, 21, 20, tzinfo=datetime.timezone.utc)}</code></pre>



<p>Now if we do not believe the message has arribed properly to the queue, we can go to the azure portal and check by ourselves. For this, we find ou storage account, click in queues and on queue1 (or whatever name you choose in terraform) and you should see the message along with the arrival time and the expiry time (by default, 7 days from now on)</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="833" height="311" src="https://www.albertnogues.com/wp-content/uploads/2020/12/QueueMessage.png" alt="" class="wp-image-962" srcset="https://www.albertnogues.com/wp-content/uploads/2020/12/QueueMessage.png 833w, https://www.albertnogues.com/wp-content/uploads/2020/12/QueueMessage-300x112.png 300w, https://www.albertnogues.com/wp-content/uploads/2020/12/QueueMessage-768x287.png 768w, https://www.albertnogues.com/wp-content/uploads/2020/12/QueueMessage-161x60.png 161w" sizes="auto, (max-width: 833px) 100vw, 833px" /></figure>



<p>Let&#8217;s see how to retrieve that message from python now. Remember that storage account queues do not delete the processed messages so If you do not delete them they will stay until expiration (even they will stay &#8220;hidden&#8221; for 90 seconds by default unless you pass other parameter) , so make sure your call deletes the message once processed (in this case read):</p>



<pre class="wp-block-code"><code>messages = queue.receive_messages()

for msg in messages:
    print(msg.content)
    queue.delete_message(msg)</code></pre>



<p>And this will output our message:</p>



<pre class="wp-block-code"><code>Hello World!</code></pre>



<p><em>If you want to only see your message without actually &#8220;reading it&#8221; you can use the <strong>peek </strong>function. This will not mark your message as &#8220;seen&#8221; and will be returned by any other consumer reading the queue or any retry you do.</em></p>



<p>If we go back to the azure portal and check the queue we should see the message is not there anymore. We can also delete the messages from the azure portal,a s well as create them directly there.</p>



<p>To improve our code a little bit we can use SAS keys instead of the storage account master keys. You can generate a SAS token directly from python with the following code:</p>



<pre class="wp-block-code"><code>from datetime import datetime, timedelta
from azure.storage.queue import QueueServiceClient, generate_account_sas, ResourceTypes, AccountSasPermissions

sas_token = generate_account_sas(
    account_name="&lt;storage-account-name&gt;",
    account_key="&lt;account-access-key&gt;",
    resource_types=ResourceTypes(service=True),
    permission=AccountSasPermissions(read=True),
    expiry=datetime.utcnow() + timedelta(hours=1)
)

queue_service_client = QueueServiceClient(account_url="https://&lt;my_account_name&gt;.queue.core.windows.net", credential=sas_token)</code></pre>



<p>But you still need to have your credentials inside the code. So the safest way to manage it is to create the SAS token from somewhere else with a caducity not long in the future and use this in your code, or use environment variables for passing sensitive information to your code. With the os library in python you can read them and use inside your code, without having to be written there and exposing them in your code or git.</p>



<p>For more information you can check microsoft official documentation <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/azure/storage/queues/storage-python-how-to-use-queue-storage?tabs=python" data-type="URL" data-id="https://docs.microsoft.com/en-us/azure/storage/queues/storage-python-how-to-use-queue-storage?tabs=python" target="_blank">here</a>, the quickstart guide <a href="https://docs.microsoft.com/en-us/azure/storage/queues/storage-quickstart-queues-python" data-type="URL" data-id="https://docs.microsoft.com/en-us/azure/storage/queues/storage-quickstart-queues-python" target="_blank" rel="noreferrer noopener">here </a>or the pypi page <a href="https://pypi.org/project/azure-storage-queue/" data-type="URL" data-id="https://pypi.org/project/azure-storage-queue/" target="_blank" rel="noreferrer noopener">here</a>.</p>
<p>The post <a href="https://www.albertnogues.com/deploying-and-interacting-with-an-azure-storage-account-and-a-queue-with-terraform-and-python-part-i/">Deploying an Azure Storage Account with a queue with terraform and python</a> appeared first on <a href="https://www.albertnogues.com">Albert Nogués</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
