<?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>Google Cloud archivos - Geko Cloud</title>
	<atom:link href="https://geko.cloud/en/tag/google-cloud-en/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Servicios de consultoría cloud y devops</description>
	<lastBuildDate>Mon, 08 Nov 2021 09:53:17 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.5.7</generator>

<image>
	<url>https://geko.cloud/wp-content/uploads/2021/08/cropped-geko-fav-150x150.png</url>
	<title>Google Cloud archivos - Geko Cloud</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>GCP Cloud SQL – Recovering an accidentally deleted database</title>
		<link>https://geko.cloud/en/gcp-cloud-sql-recover-database/</link>
					<comments>https://geko.cloud/en/gcp-cloud-sql-recover-database/#respond</comments>
		
		<dc:creator><![CDATA[Geko Cloud]]></dc:creator>
		<pubDate>Wed, 10 Mar 2021 09:29:10 +0000</pubDate>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[Google Cloud]]></category>
		<category><![CDATA[MySQL]]></category>
		<guid isPermaLink="false">https://geko2.factoryfy.com/gcp-cloud-sql-recovering-an-accidentally-deleted-database/</guid>

					<description><![CDATA[<p>Introduction It all started with a simple message: &#8220;Hello Geko, we are receiving a DB connection timeout&#8220;. It took less than 2 minutes to discover what was going on: The database was deleted. Lots of facepalms after, the main task was to recover the data (and also the service). Fortunately, Google enforces the backup policies [&#8230;]</p>
<p>La entrada <a href="https://geko.cloud/en/gcp-cloud-sql-recover-database/">GCP Cloud SQL – Recovering an accidentally deleted database</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Introduction</h2>
<p style="text-align: justify;">It all started with a simple message: &#8220;<em>Hello <a href="https://geko2.factoryfy.com/">Geko</a>, we are receiving a DB connection timeout</em>&#8220;. It took less than 2 minutes to discover what was going on: The database was deleted. Lots of facepalms after, the main task was to recover the data (and also the service). Fortunately, Google enforces the backup policies to always copy the database once per day. At Geko, we all agree with this policy. So the thing is we went to look for the <strong>backups</strong> and the nightmare began. There were no <strong>backups</strong>! There was nothing! And then we found out <strong>backups</strong> are strongly bounded to the database resource, so if the <strong>database</strong> gets deleted the <strong>backups</strong> also do. <a href="https://cloud.google.com/sql/docs/mysql/delete-instance">Google states it so clear on their docs for Cloud SQL.</a></p>
<p><img fetchpriority="high" decoding="async" class="size-full wp-image-5413 aligncenter" src="https://geko.cloud/wp-content/uploads/2021/03/google-warning-min.jpg" alt="Google warning" width="842" height="308" srcset="https://geko.cloud/wp-content/uploads/2021/03/google-warning-min.jpg 842w, https://geko.cloud/wp-content/uploads/2021/03/google-warning-min-300x110.jpg 300w, https://geko.cloud/wp-content/uploads/2021/03/google-warning-min-768x281.jpg 768w" sizes="(max-width: 842px) 100vw, 842px" /></p>
<p style="text-align: justify;">We are not going to go deeper on this post about how the database got deleted. Just tell it was an <strong>automated process</strong> which detected a <strong>disk size increase</strong> and when trying to go back to a previous, smaller size <strong>an entire database replacement was required</strong>. There was no opportunity to accept it nor stop it, so the situation was what it was:</p>
<ul>
<li>No <strong>database</strong> == No data</li>
<li>No <strong>backups</strong></li>
</ul>
<h2>What we did to resolve the situation</h2>
<p style="text-align: justify;">Even when Google was telling us the backups were deleted when the database also was, and all the facts were pointing to this hypothesis, we were still stubborn and we didn&#8217;t give up. The <strong>GCP</strong> web UI gave us no chances to recover, so we decided to continue digging by using the <strong>CLI</strong> (gcloud). <strong>And this was finally the key to our success!</strong></p>
<p style="text-align: justify;">We had the theory backups should be still somewhere even when the docs say they shouldn&#8217;t, so we checked different kinds of storage places until checking the <strong>SQL backups</strong> section. It comes that we were quick enough when checked this section, and <strong>we also knew the name of the deleted database</strong>, so we were able to run the next command.</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ gcloud sql backups list --instance=deleted-db-name --project our-project
ID             WINDOW_START_TIME              ERROR  STATUS
1614876500000  2021-03-04T04:00:00.000+00:00  -      SUCCESSFUL
1614765400000  2021-03-03T04:00:00.000+00:00  -      SUCCESSFUL
1614654300000  2021-03-02T04:00:00.000+00:00  -      SUCCESSFUL
1614543200000  2021-03-01T04:00:00.000+00:00  -      SUCCESSFUL
1614432100000  2021-02-28T04:00:00.000+00:00  -      SUCCESSFUL
1614321000000  2021-02-27T04:00:00.000+00:00  -      SUCCESSFUL
1614210000000  2021-02-26T04:00:00.000+00:00  -      SUCCESSFUL</pre>
</div>
<p style="text-align: justify;">And there they were still! After catching breath and getting our smiles back, the <strong>recovering process</strong> started. We still were not fully trusting this was going to work since maybe the backup list was there while no longer the data behind, but we had to give it a chance. <strong>We moved fast as we knew time was playing against us, so we immediately created a new database from scratch and just after we started the restoring process</strong>.</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ gcloud sql backups restore 1614876500000 --restore-instance=new-db-from-scratch-name --project our-project --backup-instance=deleted-db-name
All current data on the instance will be lost when the backup is 
restored.

Do you want to continue (Y/n)?  

Restoring Cloud SQL instance...done.                                                                                                                                                                                                        
Restored [https://sqladmin.googleapis.com/sql/v1beta4/projects/our-project/instances/new-db-from-scratch-name]</pre>
</div>
<p style="text-align: justify;">Finally, even when having positive feedback from <strong>GCP</strong>, we were still not fully believing this had worked. We needed to verify all the data was there, so we did. Fortunately again, everything was recovered. Our next and final step was to perform a <strong>SQL<em>-dump</em></strong> in order to ensure we had a recent copy at another location.</p>
<h2>Conclusion</h2>
<p style="text-align: justify;">Even after deeply searching on Google and not finding any helping results — as all of them say there&#8217;s nothing you can do — our knowledge and passion kept us continue digging on the topic until we found a way. We know we were lucky about finding the backups still there, but we know we also were <strong>quick</strong>, <strong>methodical,</strong> <strong>and</strong> <strong>obstinate </strong>when detecting and looking around to fix it. On the other hand, we have learned we cannot trust database backups performed by the provider, so we&#8217;re currently working on procedures to have backups in more places. <strong>We have pretty clear this is the first and the last time we are handling this topic</strong>.</p>
<p style="text-align: justify;">Moreover, and as opposite to AWS, as we previously mentioned <strong>GCP</strong> strongly links the database resource to its backups. This has shown up it could be a huge problem when dealing with <strong>accidental deletion</strong>. Additionally, it&#8217;s not possible to <strong>copy</strong> <strong>SQL backups</strong> to any other kind of storage. Nevertheless, there are custom solutions consisting of regularly dumping the database and then storing it on a <em>bucket</em>, but it&#8217;s not something official.</p>
<p style="text-align: justify;">On the other hand, we strongly advise being careful when having <strong>automated processes</strong> playing around. As we have seen, the only way to <strong>protect a GCP database against termination</strong> is to limit the permissions. So the way to proceed is to <strong>remove the DELETE permission</strong> from the (service) accounts the <strong>automated processes</strong> use.</p>
<p><img decoding="async" class="aligncenter wp-image-4115 size-full" src="https://geko2.factoryfy.com/wp-content/uploads/meme.jpg" alt="Joke about GCP. Geko as a strong dog says: I accidentally deleted my DB. I need a backup! ― GCP as a weak dog answers: I deleted your backups when removing the DB. It was not was you was looking for? ― And finally Geko dog replies: Ok... let me find them for you and fix all this mess!" width="468" height="420" /></p>
<p style="text-align: justify;">Thankfully, you can always count on <a href="https://geko.cloud/en/">Geko</a> team —a high-skilled <strong>engineering</strong> team— who will dig on the topic until getting it is easy and solved for you. Don’t forget to come back to the <a href="https://geko.cloud/en/blog/labs/">Geko’s blog</a> and check out what’s new in here!</p>
<h4 style="text-align: center;">The Geko team will be always glad to see you back, and also you should <a href="https://geko.cloud/en/contact/" target="_blank" rel="noopener noreferrer">contact us for further information!</a></h4>
<h4 style="text-align: center;"><a href="https://geko.cloud/en/contact/"><img decoding="async" class="aligncenter wp-image-3265" src="https://geko2.factoryfy.com/wp-content/uploads/geko-1-300x297.png" alt="" width="80" height="79" /></a></h4>
<p>La entrada <a href="https://geko.cloud/en/gcp-cloud-sql-recover-database/">GCP Cloud SQL – Recovering an accidentally deleted database</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://geko.cloud/en/gcp-cloud-sql-recover-database/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>GCP/GKE – New logging system</title>
		<link>https://geko.cloud/en/gcp-gke-new-logging-system/</link>
					<comments>https://geko.cloud/en/gcp-gke-new-logging-system/#respond</comments>
		
		<dc:creator><![CDATA[Geko Cloud]]></dc:creator>
		<pubDate>Mon, 07 Sep 2020 05:27:04 +0000</pubDate>
				<category><![CDATA[News]]></category>
		<category><![CDATA[GKE]]></category>
		<category><![CDATA[Google Cloud]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<guid isPermaLink="false">https://geko2.factoryfy.com/gcp-gke-new-logging-system/</guid>

					<description><![CDATA[<p>Introduction It&#8217;s very likely you have been running a GKE cluster at the version v1.15 for many months without issues and then -suddenly- the logs stopped being received. You are using the default logging system the system provides, so you then check the GCP status website but everything is running fine. You also know you [&#8230;]</p>
<p>La entrada <a href="https://geko.cloud/en/gcp-gke-new-logging-system/">GCP/GKE – New logging system</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2>Introduction</h2>
<p>It&#8217;s very likely you have been running a <a href="https://cloud.google.com/kubernetes-engine/docs/concepts/kubernetes-engine-overview">GKE</a> cluster at the version v1.15 for many months without issues and then -suddenly- the logs stopped being received. You are using the default logging system the system provides, so you then check the <a href="https://status.cloud.google.com/">GCP status website</a> but everything is running fine. You also know you have not modified anything on the cluster before the log stop, but at the same time you guess it has to be something on your side (on our case because it&#8217;s not happening on some other projects we manage).</p>
<p>If the above story is familiar to you continue reading as this article will cover from how to detect it, to the solution that will make your cluster logs being received again.</p>
<h2>1. Symptoms</h2>
<ol style="list-style-type: none; color: #3a3a3a; font-weight: 400;">
<li style="list-style-type: none;">
<ol style="list-style-type: none; color: #3a3a3a; font-weight: 400;">
<li>&#8211; The very first symptom you may notice is the sudden, complete absence of logs in <a href="https://en.wikipedia.org/wiki/Stackdriver">Stackdriver</a>, which should be coming -as usual- from your cluster&#8217;s pods.</li>
</ol>
</li>
</ol>
<p>&nbsp;</p>
<ol style="list-style-type: none; color: #3a3a3a; font-weight: 400;">
<li>&#8211; Beside the previous fact, you will additionally find out you have no <a href="https://en.wikipedia.org/wiki/Fluentd">Fluentd</a> agents anymore in your cluster.
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ kubectl get daemonset -n kube-system | grep -i fluentd

</pre>
</div>
</li>
<li>&#8211; On the other hand, all the nodes of your cluster have the label <strong>beta.kubernetes.io/fluentd-ds-ready=true</strong>, which is required for the Fluentd agents to know to which nodes should be deployed.
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ kubectl get nodes
NAME                           STATUS   ROLES    AGE     VERSION
gke-cluster-node-93c020-7rjq   Ready    none     14h     v1.15.11-gke.15
gke-cluster-node-93c020-9w22   Ready    none     23h     v1.15.11-gke.15
gke-cluster-node-93c020-jdbt   Ready    none     47h     v1.15.11-gke.15
gke-cluster-node-93c020-jvcl   Ready    none     3h17m   v1.15.11-gke.15

$ kubectl describe node gke-cluster-node-93c020-7rjq | grep -i fluentd-ds-ready
       beta.kubernetes.io/fluentd-ds-ready=true

$ # Do the same for the remaining nodes in order to ensure all of them are properly labeled</pre>
</div>
</li>
<li>&#8211; Your GKE cluster is currently at the version v1.15 or greater.</li>
</ol>
<h2>2. Diagnose</h2>
<p>What is currently happening is GCP forcibly deprecating the legacy monitoring/logging system. The replacement is called <a href="https://cloud.google.com/stackdriver/docs/solutions/gke">Cloud Operations for GKE</a> which (for our use case) does basically the same. Once said that, keep in mind there are a few differences you should take care about when searching (such as metric names changes), and that you will find them all on the <a href="https://cloud.google.com/stackdriver/docs/solutions/gke/migration#what-is-changing">migration guide</a>.</p>
<h2>3. Treatment</h2>
<h3>Label the cluster nodes</h3>
<p>If you found on previous steps that your cluster nodes were not labeled, do it now!</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ kubectl label node $NODE_NAME beta.kubernetes.io/fluentd-ds-ready=true</pre>
</div>
<h3>Get your cluster&#8217;s name</h3>
<p>List the available clusters.</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ gcloud container clusters list
NAME        LOCATION        MASTER_VERSION  MASTER_IP    MACHINE_TYPE   NODE_VERSION    NUM_NODES  STATUS
my-cluster  europe-east1-a  1.15.12-gke.2   34.35.36.37  n1-standard-2  1.15.11-gke.15  4          RUNNING
</pre>
</div>
<h3>Disable the logging service for your cluster</h3>
<p>Update your cluster&#8217;s config in order to set the logging service to <em>none.</em></p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ gcloud container clusters update my-cluster --logging-service none</pre>
</div>
<h3>Enable again the logging service for your cluster</h3>
<p>Update your cluster&#8217;s config in order to set the logging service to the default one.</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">$ gcloud container clusters update my-cluster --logging-service logging.googleapis.com</pre>
</div>
<p><strong>WARNING:</strong> You will get an error telling you that enabling it is not possible due to the deprecation. This is the way we finally realized where the problem was. Just move on, you are on the right way.</p>
<h3>Ensure the migration status is the expected one</h3>
<p>Open the <a href="https://console.cloud.google.com/monitoring">monitoring site at the GCP GUI</a> and then go to Settings. You will find a tab named &#8220;Kubernetes Migration Status&#8221; which should look as follows.</p>
<p><img loading="lazy" decoding="async" class="wp-image-2435 size-full alignnone" src="https://geko2.factoryfy.com/wp-content/uploads/kubernetes-migration-dashboard.png" alt="" width="871" height="554" /></p>
<h3>Fully enable the logging&amp;monitoring service for your cluster</h3>
<p>Open the <a href="https://console.cloud.google.com/kubernetes/list">GKE clusters list</a> and then click on the name of the cluster where you want to setup the new logging system. Once you see the cluster config, click on the EDIT button as is shown below.</p>
<p><img loading="lazy" decoding="async" class="size-full wp-image-2437 alignnone" src="https://geko2.factoryfy.com/wp-content/uploads/edit-cluster.png" alt="" width="731" height="213" /></p>
<p>Scroll down until finding the <span class="p6n-form-label"><span class="p6n-form-label-transclude"><strong>Kubernetes Engine Monitoring</strong> setting and then select the <strong>System and workload logging and monitoring</strong> option.</span></span></p>
<p><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2439" src="https://geko2.factoryfy.com/wp-content/uploads/monitoring-dropdown.png" alt="" width="463" height="131" /></p>
<p><strong>IMPORTANT: </strong>Don&#8217;t forget to save your changes at the bottom.</p>
<h5>And that&#8217;s it! Your cluster will receive logs again as expected!</h5>
<p>&nbsp;</p>
<h2>Conclusion</h2>
<p>As you may probably know Google Cloud Platform is still in beta, so you will often find some changes breaking your already-working systems. You have two options at this point: On the one hand you could keep yourself up to date with all the future changes and deprecations. On the other hand you could just limit yourself to fix them as soon as they appear, but keep in mind you will always be blindly fighting against them.</p>
<p>There is a third option (which should be the first one), consisting on regularly coming to the <a href="https://geko.cloud/en/blog/">Geko&#8217;s blog</a> and check out if we have already dealt with the problem you are encountering. The Geko team will be always glad to see you here <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><a href="https://geko.cloud/en/contact/" target="_blank" rel="noopener noreferrer">Contact us for further information!</a></p>
<p>La entrada <a href="https://geko.cloud/en/gcp-gke-new-logging-system/">GCP/GKE – New logging system</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://geko.cloud/en/gcp-gke-new-logging-system/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Upgrade GKE public-cluster’s Terraform module</title>
		<link>https://geko.cloud/en/upgrade-gke-public-clusters-terraform-module/</link>
					<comments>https://geko.cloud/en/upgrade-gke-public-clusters-terraform-module/#respond</comments>
		
		<dc:creator><![CDATA[Jose Luis Sánchez]]></dc:creator>
		<pubDate>Wed, 13 May 2020 06:24:40 +0000</pubDate>
				<category><![CDATA[News]]></category>
		<category><![CDATA[GKE]]></category>
		<category><![CDATA[Google Cloud]]></category>
		<category><![CDATA[Terraform]]></category>
		<guid isPermaLink="false">https://geko2.factoryfy.com/upgrade-gke-public-clusters-terraform-module/</guid>

					<description><![CDATA[<p>Introduction From time to time Google introduces new features and changes that sometimes also force the Terraform modules to upgrade themselves. It was our case at Geko, where we were using the GKE module for public-cluster deployment&#38;management at version 5.x. A few days ago, when we planned to update some parameters it came that Google [&#8230;]</p>
<p>La entrada <a href="https://geko.cloud/en/upgrade-gke-public-clusters-terraform-module/">Upgrade GKE public-cluster’s Terraform module</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Introduction</h3>
<p>From time to time Google introduces new features and changes that sometimes also force the <a href="https://www.terraform.io/docs/configuration/modules.html">Terraform modules</a> to upgrade themselves. It was our case at <a href="https://geko2.factoryfy.com/">Geko</a>, where we were using the <a href="https://registry.terraform.io/modules/terraform-google-modules/kubernetes-engine/google/5.1.1/submodules/beta-public-cluster">GKE module for public-cluster deployment&amp;management at version 5.x</a>. A few days ago, when we planned to update some parameters it came that Google had removed the support for the Kubernetes dashboard. It was completely deprecated and the module was failing because of it, so we were forced to upgrade the module in order to meet the new conditions. There were up to 3 major version upgrades available, so we decided to go for it and use the latest one. However, it was not a standalone solution as it required to handle Terraform state&#8217;s incoherences.</p>
<p>The aim of this lab is to learn how to <strong>upgrade</strong> the official <strong>Terraform module</strong> intended to deploy&amp;manage a <strong>public GKE cluster</strong>. We will specially deal with module&#8217;s (<a href="https://registry.terraform.io/modules/terraform-google-modules/kubernetes-engine/google/8.1.0/submodules/beta-public-cluster">kubernetes-engine.beta-public-cluster</a>) breaking changes, and we will manage to obtain the consistent status we previously had before the failure which preceded the upgrade.</p>
<p><strong>Estimated time to finish this lab</strong>: ~20 minutes</p>
<h3>1. Remove the previous resources</h3>
<p><strong>It&#8217;s strongly encouraged to perform a <em>tfstate</em> file backup before continue!</strong></p>
<p>It&#8217;s especially important to remove all the conflicting resources from the Terraform state as soon as they are bounded between them using dependencies. The goal here is to remove any deprecated binding prior to importing them again from the current &#8220;picture&#8221; there&#8217;s already deployed.</p>
<p>The main components on a Kubernetes cluster are the networks (and subnetworks), the node pool and the cluster itself. Let&#8217;s focus on them.</p>
<div class="wp-block-codemirror-blocks code-block">
<pre class="CodeMirror" data-setting="{">terraform state rm module.gke.google_container_cluster.primary
terraform state rm module.gke.google_container_node_pool.pools[0]
terraform state rm module.vpc.google_compute_network.network
terraform state rm module.vpc.google_compute_subnetwork.subnetwork[0]
terraform state rm module.vpc.google_compute_subnetwork.subnetwork[1]</pre>
</div>
<h3>2. Upgrade versions</h3>
<p>Once removed the previous states the next step is to set the version for the required modules to the current latest version. For the GKE module the latest now it&#8217;s 8.1.0, but it will be allowed to automatically adopt minor upgrades (&#8220;~&gt;&#8221;).</p>
<h5>Upgrade the GKE cluster module</h5>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{"> module "gke" {
   source  = "terraform-google-modules/kubernetes-engine/google//modules/beta-public-cluster"
-  version = "~&gt; 5.0"
+  version = "~&gt; 8.1"
</pre>
</div>
<h5>Upgrade the VPC module</h5>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{"> module "vpc" {
-  source  = "github.com/terraform-google-modules/terraform-google-network?ref=v1.1.0"
+  source  = "github.com/terraform-google-modules/terraform-google-network?ref=v2.3.0"</pre>
</div>
<h5>Check the new resources</h5>
<p>In order to find out if the new resources have experienced a name change (due to the modules upgrade), a <a href="https://www.terraform.io/docs/commands/plan.html"><strong>Terraform plan</strong></a> is strongly encouraged.</p>
<p>On this case it has been found that some module&#8217;s internal hierarchy and also list&#8217;s indexes have changed.</p>
<div class="wp-block-codemirror-blocks code-block">
<pre class="CodeMirror" data-setting="{">  module.gke.google_container_cluster.primary
  
<b>-</b> module.gke.google_container_node_pool.pools[0]
<b>+</b> module.gke.google_container_node_pool.pools["default-node-pool"]

  module.vpc.google_compute_network.network
  
<b>-</b> module.vpc.google_compute_subnetwork.subnetwork[0]
<b>+</b> module.vpc.module.subnets.google_compute_subnetwork.subnetwork["southamerica-east1/my-cluster-public"]

<b>-</b> module.vpc.google_compute_subnetwork.subnetwork[1]
<b>+</b> module.vpc.module.subnets.google_compute_subnetwork.subnetwork["southamerica-east1/my-cluster-private"]</pre>
</div>
<h3>3. Import fresh resources</h3>
<p>Keep in mind that the zone/region depends on your kind of cluster. If it&#8217;s zonal you must use the master zone (e.g. <em>southamerica-east1-a</em>). On the other hand, if it&#8217;s a regional cluster you must use the region (e.g. <em>southamerica-east1</em>). The following example assumes a regional cluster located at <em>southamerica-east1</em>, in the project &#8220;<strong>my-project</strong>&#8220;, and with a cluster name &#8220;<strong>my-cluster</strong>&#8220;. The network names were set accordingly to the cluster&#8217;s name, just adding the suffixes &#8220;private&#8221; and &#8220;public&#8221; to the subnets to properly differentiate them.</p>
<p><strong>Note also the new module hierarchy and indexing.</strong></p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{"># Global vars
REGION="southamerica-east1"
PROJECT="my-project"
CLUSTER="my-cluster"

# Cluster
CLUSTER_LOCAL="module.gke.google_container_cluster.primary"
CLUSTER_REMOTE="${PROJECT}/${REGION}/${CLUSTER}"
terraform import $CLUSTER_LOCAL $CLUSTER_REMOTE

# Node pool
POOL_LOCAL="module.gke.google_container_node_pool.pools["default-node-pool"]"
POOL_REMOTE="${CLUSTER_REMOTE}/default-node-pool"
terraform import $POOL_LOCAL $POOL_REMOTE

# Subnetworks
BASE_SUBNET_LOCAL="module.vpc.module.subnets.google_compute_subnetwork.subnetwork"

## Public
PUBLIC_SUBNET_LOCAL="${BASE_SUBNET_LOCAL}["${REGION}/${CLUSTER}-public"]"
PUBLIC_SUBNET_REMOTE="${CLUSTER_REMOTE}-public"
terraform import $PUBLIC_SUBNET_LOCAL $PUBLIC_SUBNET_REMOTE

## Private
PRIVATE_SUBNET_LOCAL="${BASE_SUBNET_LOCAL}["${REGION}/${CLUSTER}-private"]"
PRIVATE_SUBNET_REMOTE="${CLUSTER_REMOTE}-private"
terraform import $PRIVATE_SUBNET_LOCAL $PRIVATE_SUBNET_REMOTE

# Network
NETWORK_LOCAL="module.vpc.module.vpc.google_compute_network.network"
NETWORK_REMOTE="${PROJECT}/${CLUSTER}"
terraform import $NETWORK_LOCAL $NETWORK_REMOTE</pre>
</div>
<h3> 4. Update parameters</h3>
<p>It&#8217;s very likely you will encounter that after a Terraform plan the <strong><em>google_container_cluster</em> </strong>resource still needs to be updated due to a <em>subnetwork</em> parameter change. The new subnet keys have made the indexes to change their order. Just edit your GKE module to replace the <em>subnetwork</em> parameter as below.</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{"><b>-</b> subnetwork = module.vpc.subnets_names[<b>0</b>]
<b>+</b> subnetwork = module.vpc.subnets_names[<b>1</b>]</pre>
</div>
<h3>Conclusion</h3>
<p>As you may have read above, sometimes -when relying on third parties- could happen that a breaking change is introduced and you get yourself into troubles to get the service back again. Beside this, the solution could introduce collateral damages which will require additional sub-solutions. On this particular case regarding Terraform, dealing with inconsistent states is not really common nor recommended, but it comes that is the only method you have available to solve them on your tool-set.</p>
<hr />
<p>I hope you&#8217;ve enjoyed this post and I encourage you to <a href="https://geko.cloud/en/blog/">check our blog for other posts</a> that you might find helpful. <a href="https://geko.cloud/en/contact/">Do not hesitate to contact us</a> if you would like us to help you on your projects.</p>
<p>See you on the next post!</p>
<p>La entrada <a href="https://geko.cloud/en/upgrade-gke-public-clusters-terraform-module/">Upgrade GKE public-cluster’s Terraform module</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://geko.cloud/en/upgrade-gke-public-clusters-terraform-module/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to run Grafana in docker with Google SSO</title>
		<link>https://geko.cloud/en/how-to-run-grafana-in-docker-with-google-sso/</link>
					<comments>https://geko.cloud/en/how-to-run-grafana-in-docker-with-google-sso/#respond</comments>
		
		<dc:creator><![CDATA[Xavi Miranda]]></dc:creator>
		<pubDate>Mon, 04 May 2020 13:12:36 +0000</pubDate>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Google Cloud]]></category>
		<category><![CDATA[Grafana]]></category>
		<guid isPermaLink="false">https://geko2.factoryfy.com/how-to-run-grafana-in-docker-with-google-sso/</guid>

					<description><![CDATA[<p>The aim of this lab is to learn how to setup Google SSO Authentication in Grafana and also how to demonstrate how fast we can spin up a new Grafana instance using the official docker container (no need to create custom images). If you are looking on how to setup LDAP authentication you can check [&#8230;]</p>
<p>La entrada <a href="https://geko.cloud/en/how-to-run-grafana-in-docker-with-google-sso/">How to run Grafana in docker with Google SSO</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The aim of this lab is to learn how to setup <strong>Google SSO Authentication</strong> in Grafana and also how to demonstrate how fast we can spin up a new Grafana instance using the <strong>official docker container</strong> (no need to create custom images). If you are looking on how to setup <strong>LDAP authentication</strong> <a href="https://geko.cloud/en/install-grafana-ldap-kubernetes-helm/">you can check this post</a>.</p>
<p>In Geko we decided to implement SSO with most of our internal services since we already work with Gsuite accounts, so it was the obvious way to go. Anyway you can keep the default user management functional if you still want to use it.</p>
<p>Using SSO also makes it a lot easier for us when there are new incorporations in our team since they can <strong>sign up straight forward</strong> and we just need to set roles for them afterwards. Even for our clients we can allow their domains to set up accounts for them, if needed.</p>
<p><strong>Estimated time to finish this lab</strong>: 20-30 minutes</p>
<h3>Setup Google Cloud account</h3>
<p>To set up SSO we need to create some credentials in Google Cloud. If you don’t have a project created in GCP you will have to create one: https://console.cloud.google.com</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1813" src="https://geko2.factoryfy.com/wp-content/uploads/image1.png" alt="GCP New Project" width="447" height="312" /></p>
<h4>Oauth consent screen</h4>
<p>The consent screen is what users will see when they try to login to your application (Grafana). You can use this link to get to the configuration: https://console.cloud.google.com/apis/credentials/consent/edit?</p>
<p>Here we can set some parameters to customize our consent screen. We are going to set the following values for this lab:</p>
<ul>
<li><strong>Application name</strong>: Grafana</li>
<li><strong>Support email</strong>: Your email or any mail associated with your account</li>
<li><strong>Authorized domains</strong>: These are the domains against which your users will be able to authenticate. You will usually use your organization domain name but you might be interested in allowing others too.</li>
</ul>
<p>As you can see the configuration is pretty straight forward. If you want to set any other parameter feel free, it’s up to you.</p>
<h4>Creating credentials</h4>
<p>We will now set up the credentials that will be used in Grafana to authenticate against our Google Cloud project: https://console.cloud.google.com/apis/credentials?</p>
<ul>
<li>Click on “CREATE CREDENTIALS” and then “Oauth Client ID”.</li>
<li>Select “Web application”, set the name to “Grafana“ and click “Create”</li>
</ul>
<p>Next, you will see a popup window with the following information:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1814" src="https://geko2.factoryfy.com/wp-content/uploads/imagen2.png" alt="GCP Oauth2 client created" width="396" height="260" /></p>
<p><strong>Warning!</strong> Store your Client ID and Client Secret in a secure location.</p>
<h3>Setup Grafana</h3>
<p>I assume you already have setup docker service in your local machine. If you have not, get started here: https://docs.docker.com/get-docker/</p>
<h4>Persistent volume</h4>
<p>Even if we do use docker we want to have persistent data so any modification in configuration or dashboards will not get lost even if we kill the container. This makes upgrades to newer versions really easy and less painfully. So go ahead and create a volume for Grafana:</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">docker volume create grafana-data</pre>
</div>
<h4>Prepare the arguments to setup Grafana</h4>
<p>We are going to spin up the Grafana container using some <strong>environment variables</strong> to setup Grafana. Here we will describe what is each one for:</p>
<ul>
<li>GF_SECURITY_ADMIN_PASSWORD: Strong random password</li>
<li>GF_SERVER_ROOT_URL: Set this if you want to override the server root. Otherwise you can remove this parameter. Useful if you run Grafana behind a reverse proxy (for example nginx) and need to access a specific uri.</li>
<li>GF_AUTH_GOOGLE_ENABLED: Enable Google SSO</li>
<li>GF_AUTH_GOOGLE_AUTH_URL: Self explanatory</li>
<li>GF_AUTH_GOOGLE_TOKEN_URL: Self explanatory</li>
<li>GF_AUTH_GOOGLE_CLIENT_SECRET: Client Secret that we obtained when we created the credentials in GCP</li>
<li>GF_AUTH_GOOGLE_CLIENT_ID: Client ID that we obtained when we created the credentials in GCP</li>
<li>GF_ALLOWED_DOMAINS: Your company domain and every other domain you want to grant access to (for example your clients)</li>
</ul>
<p>We can of course set all these parameters in grafana.ini instead of using environment vars, it’s your choice which method to use.</p>
<h4>Start Grafana container with our custom arguments</h4>
<p>We can now spin up our container. Note that we are mapping the Grafana port to our host 8081 port:</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">docker run -d --rm -p 8081:3000 --name grafana 
    -e "GF_SECURITY_ADMIN_PASSWORD=&lt;<b>some_password</b>&gt;" 
    -e "GF_SERVER_ROOT_URL=<a href="http://&lt;your_ip&gt;">http://</a>" 
    -e "GF_AUTH_BASIC_ENABLED=&lt;<b>disable_default_auth</b>&gt;" 
    -e "GF_AUTH_GOOGLE_ENABLED=&lt;<b>enable_google_auth</b>&gt;" 
    -e "GF_AUTH_GOOGLE_AUTH_URL=https://accounts.google.com/o/oauth2/auth" 
    -e "GF_AUTH_GOOGLE_TOKEN_URL=https://accounts.google.com/o/oauth2/token" 
    -e "GF_AUTH_GOOGLE_CLIENT_SECRET=&lt;<b>your_client_secret</b>&gt;" 
    -e "GF_AUTH_GOOGLE_CLIENT_ID=&lt;<b>your_client_id</b>&gt;" 
    -e “GF_ALLOWED_DOMAINS=&lt;<b>your_company_domain</b>&gt;”
    -v grafana-storage:/var/lib/grafana 
grafana/grafana</pre>
</div>
<p>If everything is fine you should be able to access grafana at http://localhost:8081 and will see a button to authenticate with Google:</p>
<p><img loading="lazy" decoding="async" class="aligncenter wp-image-1816" src="https://geko2.factoryfy.com/wp-content/uploads/imagen3.png" alt="GrafanaSSO" width="546" height="359" /></p>
<p>If you try to sign in with a gmail account that belongs to an allowed domain you should be able to access Grafana now.</p>
<hr />
<p>I hope you&#8217;ve enjoyed this post and I encourage you to <a href="https://geko.cloud/en/blog/">check our blog for other posts</a> that you might find helpful, such as &#8220;<a href="https://geko.cloud/en/what-is-kubernetes/">What is the kubernetes?</a>&#8220;. <a href="https://geko.cloud/en/contact/">Do not hesitate to contact us</a> if you would like us to help you with your projects.</p>
<p>See you in the next post!</p>
<p>La entrada <a href="https://geko.cloud/en/how-to-run-grafana-in-docker-with-google-sso/">How to run Grafana in docker with Google SSO</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://geko.cloud/en/how-to-run-grafana-in-docker-with-google-sso/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to set up a High-Availability HAProxy in Google Cloud with Keepalived</title>
		<link>https://geko.cloud/en/setup-haproxy-googlecloud-keepalived/</link>
					<comments>https://geko.cloud/en/setup-haproxy-googlecloud-keepalived/#respond</comments>
		
		<dc:creator><![CDATA[Jose Luis Sánchez]]></dc:creator>
		<pubDate>Mon, 02 Mar 2020 08:13:25 +0000</pubDate>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[Google Cloud]]></category>
		<category><![CDATA[HAproxy]]></category>
		<guid isPermaLink="false">https://geko2.factoryfy.com/how-to-set-up-a-high-availability-haproxy-in-google-cloud-with-keepalived/</guid>

					<description><![CDATA[<p>Yes, you may think: &#8220;What? Google Cloud has it&#8217;s own load balancer managed service. Why you want to configure and manage a dedicated HA load balancer?&#8220;. We recommend using GCP Load Balancer service always as you can. It&#8217;s a very reliable service and you don&#8217;t have to manage your own load balancer in a High-Availability [&#8230;]</p>
<p>La entrada <a href="https://geko.cloud/en/setup-haproxy-googlecloud-keepalived/">How to set up a High-Availability HAProxy in Google Cloud with Keepalived</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Yes, you may think:<em> &#8220;What? Google Cloud has it&#8217;s own load balancer managed service. Why you want to configure and manage a dedicated HA load balancer?</em>&#8220;. We recommend using GCP Load Balancer service always as you can. It&#8217;s a very reliable service and you don&#8217;t have to manage your own load balancer in a High-Availability configuration.</p>
<p>But sometimes there are some situations that the GCP Load Balancer doesn&#8217;t fit your needs or, simply you don&#8217;t want to use it&#8230; In those cases we have a very simple configuration using two well known pieces of software: <strong>HAProxy</strong> and <strong>Keepalived</strong>.</p>
<p>Keepalived uses Virtual Router Redundancy Protocol (<a href="https://tools.ietf.org/html/rfc3768" target="external" rel="noopener noreferrer">VRRP</a>) and floating IP addresses that can &#8216;move&#8217; from one VM to another in case of one of them becomes unavailable. In a classic and on-prem environment this is something like that:</p>
<figure id="attachment_912" aria-describedby="caption-attachment-912" style="width: 634px" class="wp-caption aligncenter"><a href="https://geko2.factoryfy.com/wp-content/uploads/floating-ip-on-premises-environment.svg"><img loading="lazy" decoding="async" class="wp-image-912 " src="https://geko2.factoryfy.com/wp-content/uploads/floating-ip-on-premises-environment.svg" alt="" width="634" height="181" /></a><figcaption id="caption-attachment-912" class="wp-caption-text">Image source: Google Cloud</figcaption></figure>
<p>In case of a server failure, when the other server takes over the floating IP addresses, it adds these addresses to its network interface. The server announces this takeover to other devices using Layer 2 by sending a <a href="https://en.wikipedia.org/wiki/Address_Resolution_Protocol#ARP_announcements" target="external" rel="noopener noreferrer">gratuitous Address Resolution Protocol (ARP) frame</a>. Google Compute Engine uses a virtualized network stack and typical implementation mechanisms don&#8217;t work here. The VPC network handles ARP requests based on the configured routing topology, and ignores gratuitous ARP frames.</p>
<p>First of all, you need to install haproxy and keepalived in your server. In this case, we used <strong>Ubuntu 18.04</strong>. Just run:</p>
<pre>sudo apt install haproxy 
sudo apt install keepalived</pre>
<p>For this tutorial we will configure an <strong>internal load balancer</strong> but you can also configure an external load balancer with some small modifications.</p>
<p><img loading="lazy" decoding="async" class="wp-image-945 aligncenter" src="https://geko2.factoryfy.com/wp-content/uploads/screenshot-20200228160149-911x611.png" alt="" width="619" height="415" /></p>
<p>We&#8217;ll use this <span style="font-weight: 400;"><strong>/etc/haproxy/haproxy.cfg</strong> file in both servers. Both servers (MASTER and BACKUP) <strong>need to have exactly <span style="text-decoration: underline;">the same</span> HAProxy configuration</strong>.</span></p>
<pre><span style="font-weight: 400;">global</span>
<span style="font-weight: 400;">        log /dev/log    local0 debug
</span><span style="font-weight: 400;">        log /dev/log    local1 debug</span>
<span style="font-weight: 400;">        chroot /var/lib/haproxy</span>
<span style="font-weight: 400;">        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners</span>
<span style="font-weight: 400;">        stats timeout 30s</span>
<span style="font-weight: 400;">        user haproxy</span>
<span style="font-weight: 400;">        group haproxy</span>
<span style="font-weight: 400;">        daemon</span>

<span style="font-weight: 400;">defaults</span>
<span style="font-weight: 400;">        log     global</span>
<span style="font-weight: 400;">        mode    http</span>
<span style="font-weight: 400;">        option  dontlognull</span>
<span style="font-weight: 400;">        timeout connect 5000</span>
<span style="font-weight: 400;">        timeout client  50000</span>
<span style="font-weight: 400;">        timeout server  50000</span>
<span style="font-weight: 400;">        errorfile 400 /etc/haproxy/errors/400.http</span>
<span style="font-weight: 400;">        errorfile 403 /etc/haproxy/errors/403.http</span>
<span style="font-weight: 400;">        errorfile 408 /etc/haproxy/errors/408.http</span>
<span style="font-weight: 400;">        errorfile 500 /etc/haproxy/errors/500.http</span>
<span style="font-weight: 400;">        errorfile 502 /etc/haproxy/errors/502.http</span>
<span style="font-weight: 400;">        errorfile 503 /etc/haproxy/errors/503.http</span>
<span style="font-weight: 400;">        errorfile 504 /etc/haproxy/errors/504.http</span>

<span style="font-weight: 400;">frontend service-1</span>
<span style="font-weight: 400;">  bind 192.168.240.140:443</span>
<span style="font-weight: 400;">  mode tcp</span>
<span style="font-weight: 400;">  option tcplog</span>
<span style="font-weight: 400;">  log global</span>
<span style="font-weight: 400;">  default_backend service-1-be</span>
<span style="font-weight: 400;">backend service-1-be</span>
<span style="font-weight: 400;">  mode tcp</span>
<span style="font-weight: 400;">  server service-1-server-1 10.152.0.220:443 check id 1
  server service-1-server-2 10.152.0.221:443 check id 2


</span>frontend service-2
  bind 192.168.240.141:443
  mode tcp
  option tcplog
  log global
  default_backend service-2-be
backend service-2-be
  mode tcp
  server service-2-server-1 10.10.0.40:443 check id 1
  server service-2-server-2 10.10.0.41:443 check id 2</pre>
<p>In this example, the two floating IPs will be: <strong>192.168.240.140</strong> and <strong>192.168.240.141</strong>.</p>
<p>Don&#8217;t forget to restart the haproxy service(sudo systemctl restart haproxy) every time you change the config file. <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>For the<b> /etc/keepalived/keepalived.conf</b> configuration file we will use these two config files in the master and slave VMs:</p>
<h3>MASTER</h3>
<pre><span style="font-weight: 400;">vrrp_instance floating_ip {</span>
<span style="font-weight: 400;">    state MASTER</span>
<span style="font-weight: 400;">    interface ens4</span>
<span style="font-weight: 400;">    unicast_src_ip 192.168.240.10</span>
<span style="font-weight: 400;">    unicast_peer {</span>
<span style="font-weight: 400;">        192.168.240.11</span>
<span style="font-weight: 400;">    }</span>

<span style="font-weight: 400;">    virtual_router_id 50</span>
<span style="font-weight: 400;">    priority 100</span>
<span style="font-weight: 400;">    authentication {</span>
<span style="font-weight: 400;">        auth_type PASS</span>
<span style="font-weight: 400;">        auth_pass your_passwd</span>
<span style="font-weight: 400;">    }</span>
<span style="font-weight: 400;">    notify_master /etc/keepalived/takeover.sh root</span>
<span style="font-weight: 400;">}</span></pre>
<h3>BACKUP</h3>
<pre>vrrp_instance floating_ip {
    state BACKUP
    interface ens4
    unicast_src_ip 192.168.240.11
    unicast_peer {
        192.168.240.10
    }

    virtual_router_id 50
    priority 50
    authentication {
        auth_type PASS
        auth_pass your_passwd
    }
    notify_master /etc/keepalived/takeover.sh root
}</pre>
<p>Don&#8217;t forget to restart the keepalived service (sudo systemctl restart keepalived) every time you change the config file. <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>And now the part that does the &#8216;magic&#8217;: the <strong>/etc/keepalived/takeover.sh</strong> script. Basically, this script unassigns IP aliases from the peer that is down and assigns them to himself. After that, haproxy service is reloaded to allow haproxy to bind to the floating IPs.</p>
<h3>MASTER</h3>
<pre># Unassign peer's IP aliases. Try it until it's possible.
until gcloud compute instances network-interfaces update haproxy-prod-backup --zone europe-west1-c --aliases "" &gt; /etc/keepalived/takeover.log 2&gt;&amp;1; do
    echo "Instance not accessible during takeover. Retrying in 5 seconds..."
    sleep 5
done

# Assign IP aliases to me because now I am the MASTER!
gcloud compute instances network-interfaces update haproxy-prod 
    --zone europe-west1-b 
    --aliases "192.168.240.140/32;192.168.240.141/32" &gt;&gt; /etc/keepalived/takeover.log 2&gt;&amp;1
systemctl restart haproxy
echo "I became the MASTER at: $(date)" &gt;&gt; /etc/keepalived/takeover.log

</pre>
<h3>BACKUP</h3>
<pre># Unassign peer's IP aliases. Try it until it's possible.
until gcloud compute instances network-interfaces update haproxy-prod --zone europe-west1-b --aliases "" &gt; /etc/keepalived/takeover.log 2&gt;&amp;1; do
    echo "Instance not accessible during takeover. Retrying in 5 seconds..."
    sleep 5
done

# Assign IP aliases to me because now I am the MASTER!
gcloud compute instances network-interfaces update haproxy-prod-backup 
    --zone europe-west1-c 
    --aliases "192.168.240.140/32;192.168.240.141/32" &gt;&gt; /etc/keepalived/takeover.log 2&gt;&amp;1
systemctl restart haproxy
echo "I became the MASTER at: $(date)" &gt;&gt; /etc/keepalived/takeover.log
</pre>
<p>In fact, all that we do is assign/unassing IP alias depending on what VM is the MASTER.</p>
<p>Easy, isn&#8217;t it? <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<hr />
<p>I hope you&#8217;ve enjoyed this post and I encourage you to <a href="https://geko.cloud/en/blog/">check our blog for other posts</a> that you might find helpful, such as &#8220;<a href="https://geko.cloud/en/what-is-the-cloud/">What is the cloud?</a>&#8220;. <a href="https://geko.cloud/en/contact/">Do not hesitate to contact us</a> if you would like us to help you on your projects.</p>
<p>See you on the next post!</p>
<p>La entrada <a href="https://geko.cloud/en/setup-haproxy-googlecloud-keepalived/">How to set up a High-Availability HAProxy in Google Cloud with Keepalived</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://geko.cloud/en/setup-haproxy-googlecloud-keepalived/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Forward real IP to a NGINX behind a GCP Load Balancer</title>
		<link>https://geko.cloud/en/forward-real-ip-to-a-nginx-behind-a-gcp-load-balancer/</link>
					<comments>https://geko.cloud/en/forward-real-ip-to-a-nginx-behind-a-gcp-load-balancer/#respond</comments>
		
		<dc:creator><![CDATA[Xavi Miranda]]></dc:creator>
		<pubDate>Fri, 28 Feb 2020 12:26:06 +0000</pubDate>
				<category><![CDATA[Labs]]></category>
		<category><![CDATA[Google Cloud]]></category>
		<category><![CDATA[Ngnix]]></category>
		<guid isPermaLink="false">https://geko2.factoryfy.com/forward-real-ip-to-a-nginx-behind-a-gcp-load-balancer/</guid>

					<description><![CDATA[<p>This article focuses in GCP Load Balancers, but can apply to other cloud providers / proxy servers. Introduction We worked in a project that required a nginx server to be able to whitelist some public ip addresses while denying all other connections. While this can be addressed using GCP firewall rules there were some other [&#8230;]</p>
<p>La entrada <a href="https://geko.cloud/en/forward-real-ip-to-a-nginx-behind-a-gcp-load-balancer/">Forward real IP to a NGINX behind a GCP Load Balancer</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p style="text-align: center;"><span style="color: #000000;"><em>This article focuses in GCP Load Balancers, but can apply to other cloud providers / proxy servers.</em></span></p>
<h2><span style="color: #000000;"><strong>Introduction</strong></span></h2>
<p><span style="color: #000000;">We worked in a project that required a nginx server to be able to whitelist some public ip addresses while denying all other connections. While this can be addressed using GCP firewall rules there were some other reasons why it was necessary to be done through nginx configuration instead of using GCP rules.</span></p>
<p><span style="color: #000000;">The problem is that nginx was not showing the correct <strong>real ip address</strong> of the request in the <strong>REMOTE_ADDR</strong> header.</span></p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">130.211.0.230 - - [23/Jan/2020:09:44:51 +0000] "GET / HTTP/1.1" 404 "108.26.106.168, 36.129.221.25"</pre>
</div>
<h2><span style="color: #000000;"><strong>Scenario</strong></span></h2>
<p><span style="color: #000000;">I&#8217;ll be using a very simple scenario:</span></p>
<ul>
<li><span style="color: #000000;">Google Compute private instance running two docker containers: nginx and a php based app</span></li>
<li><span style="color: #000000;">Public GCP Load Balancer targeting the nginx container.</span></li>
</ul>
<p>Fake IP addresses used in this post:</p>
<ul>
<li>User originating requests: 108.26.106.168</li>
<li>GCP Load Balancer public IP: 36.129.221.25</li>
<li>GCP Load Balancer private ranges: 130.211.0.0/22 and 35.191.0.0/16</li>
</ul>
<p>That&#8217;s it.</p>
<h2><span style="color: #000000;"><strong>The problem</strong></span></h2>
<p><span style="color: #000000;">Let&#8217;s quickly review how a Load Balancer works: When a request is received from a remote client it is terminated and a <strong>new request </strong>is issued from the LB against the backend, forwarding a set of headers (click on <a href="https://cloud.google.com/load-balancing/docs/https#target-proxies"><strong>GCP</strong></a> and <a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html"><strong>AWS</strong></a> for specific details) that are then catched by the underlying service.</span></p>
<p><span style="color: #000000;">When you place a nginx server behind the LB you receive the <strong>Load Balancer&#8217;s private IP</strong> as remote address instead of the<strong> user&#8217;s real public ip</strong>.</span></p>
<p><span style="color: #000000;"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-828" src="https://geko2.factoryfy.com/wp-content/uploads/travolta-1.gif" alt="" width="426" height="213" /></span></p>
<p>If we take a look at nginx logs we can see this:</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">130.211.0.130 - - [23/Jan/2020:09:02:51 +0000] "GET / HTTP/1.1" 200 "108.26.106.168, 36.129.221.25"</pre>
</div>
<p>Wait! The user IP address appears in that chain at the end of the log. Why the heck is nginx taking the private range of the LB as the origin ip address? Well, this is because the LB is actually doing a new request.</p>
<h2><span style="color: #000000;"><strong>How did we solve the issue</strong></span></h2>
<p><span style="color: #000000;">The first IP in the log comes from the <strong>REMOTE_ADDR</strong> header. We need to replace the value of this header with the real ip address received in the <strong>X-Forwarded-For</strong> header.</span></p>
<p><span style="color: #000000;">But there&#8217;s something else we need to deal with this second header: It actually comes not only with the user real IP but with the Load Balancer public address too.</span></p>
<p>In order to solve all this we will use <span style="color: #000000;">the <a href="https://nginx.org/en/docs/http/ngx_http_realip_module.html"><strong>real_ip module</strong></a>. We are going to apply the following configuration in nginx.conf inside the &#8220;server&#8221; block:</span></p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">set_real_ip_from 36.129.221.25/32; // LB Public IP address
set_real_ip_from 130.211.0.0/22; // Private IP range for GCP Load Balancers
set_real_ip_from 35.191.0.0/16; //Private IP range for GCP Load Balancers
real_ip_header X-Forwarded-For;
real_ip_recursive on;</pre>
</div>
<p><span style="color: #000000;">Let&#8217;s split it down:</span></p>
<ul>
<li><span style="color: #000000;"><strong>set_real_ip_from</strong>: Tell nginx to trust GCP LB public and private IPs.</span></li>
<li><span style="color: #000000;"><strong>real_ip_header</strong>: Replace REMOTE_ADDR header with the values from X-Forwarded-For.</span></li>
<li><span style="color: #000000;"><strong>real_ip_recursive on</strong>: Filter out the trusted ips from the chain, therefore the last non-trusted address in the chain will be used as the remote address.</span></li>
</ul>
<p>Finally test it out:</p>
<div class="wp-block-codemirror-blocks code-block ">
<pre class="CodeMirror" data-setting="{">108.26.106.168 - - [23/Jan/2020:09:44:51 +0000] "GET / HTTP/1.1" 200 "108.26.106.168, 36.129.221.25"</pre>
</div>
<h2><strong>Conclusion</strong></h2>
<p>As we can see the solution was pretty straight forward, but still it took some time diving into documentation to understand how the Load Balancer was forwarding the headers and how we can tune nginx to rewrite the headers in order to achieve the expected behaviour.</p>
<p>Nevertheless it was a good learning experience.</p>
<p><span style="color: #000000;">Sources: <a href="https://nginx.org/en/docs/http/ngx_http_realip_module.html"><strong>https://nginx.org/en/docs/http/ngx_http_realip_module.html</strong></a></span></p>
<hr />
<p>I hope you&#8217;ve enjoyed this post and I encourage you to <a href="https://geko.cloud/en/blog/">check our blog for other posts</a> that you might find helpful, such as &#8220;<a href="https://geko.cloud/en/what-is-the-cloud/">What is the cloud?</a>&#8220;. <a href="https://geko.cloud/en/contact/">Do not hesitate to contact us</a> if you would like us to help you on your projects.</p>
<p>See you on the next post!</p>
<p>La entrada <a href="https://geko.cloud/en/forward-real-ip-to-a-nginx-behind-a-gcp-load-balancer/">Forward real IP to a NGINX behind a GCP Load Balancer</a> se publicó primero en <a href="https://geko.cloud/en/">Geko Cloud</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://geko.cloud/en/forward-real-ip-to-a-nginx-behind-a-gcp-load-balancer/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
