<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: langyizhao</title>
    <description>The latest articles on DEV Community by langyizhao (@langyizhao).</description>
    <link>https://dev.to/langyizhao</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F254789%2F979699f7-ad59-4c1a-97c0-a32ee8a03102.jpg</url>
      <title>DEV Community: langyizhao</title>
      <link>https://dev.to/langyizhao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/langyizhao"/>
    <language>en</language>
    <item>
      <title>Kotlin Scala Differences Cheat Sheet</title>
      <dc:creator>langyizhao</dc:creator>
      <pubDate>Thu, 02 Dec 2021 15:57:02 +0000</pubDate>
      <link>https://dev.to/langyizhao/kotlin-notes-from-a-scala-user-4a7l</link>
      <guid>https://dev.to/langyizhao/kotlin-notes-from-a-scala-user-4a7l</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Kotlin&lt;/th&gt;
&lt;th&gt;Scala&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Function Keyword&lt;/td&gt;
&lt;td&gt;fun&lt;/td&gt;
&lt;td&gt;def&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nullability&lt;/td&gt;
&lt;td&gt;Default not nullable except by adding ? at the end of variable type&lt;/td&gt;
&lt;td&gt;Null is discouraged, but no hard check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Null Check&lt;/td&gt;
&lt;td&gt;Use &lt;a href="https://kotlinlang.org/docs/null-safety.html#safe-calls"&gt;?.&lt;/a&gt; and/or &lt;a href="https://kotlinlang.org/docs/null-safety.html#elvis-operator"&gt;?:&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Use &lt;a href="https://www.scala-lang.org/api/2.13.6/scala/Option.html"&gt;Option&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lambda/Anonymous Functions&lt;/td&gt;
&lt;td&gt;Need to be surrounded with {}&lt;/td&gt;
&lt;td&gt;Can be used anywhere&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Covariant&lt;/td&gt;
&lt;td&gt;[out T]&lt;/td&gt;
&lt;td&gt;[+T]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contravariant&lt;/td&gt;
&lt;td&gt;[in T]&lt;/td&gt;
&lt;td&gt;[-T]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pattern Matching&lt;/td&gt;
&lt;td&gt;(partial) when statement&lt;/td&gt;
&lt;td&gt;(full) match/case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default Case&lt;/td&gt;
&lt;td&gt;&lt;code&gt;else -&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;case _ =&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loop a Range&lt;/td&gt;
&lt;td&gt;i in 1..10 step 2 (closed)    i in 1 until 10 step 2 (half-closed)&lt;/td&gt;
&lt;td&gt;i &amp;lt;- 1 to 10 by 2 (closed)    i in 1 until 10 by 2 (half-closed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read File into Strings&lt;/td&gt;
&lt;td&gt;File(fileName).useLines { it.toList() }&lt;/td&gt;
&lt;td&gt;scala.io.Source.fromFile("file.txt").mkString&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://docs.scala-lang.org/tour/for-comprehensions.html"&gt;For Comprehension (for/yield)&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;No Equivalent&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Companion Object&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;companion object&lt;/code&gt; keyword inside class&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;object&lt;/code&gt; keyword besides class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New Immutable Sequence&lt;/td&gt;
&lt;td&gt;listOf("one", "two", "one")&lt;/td&gt;
&lt;td&gt;Seq("one", "two", "one")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New Immutable Set&lt;/td&gt;
&lt;td&gt;setOf("one", "two", "three")&lt;/td&gt;
&lt;td&gt;Set("one", "two", "one")&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New Immutable Map&lt;/td&gt;
&lt;td&gt;mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)&lt;/td&gt;
&lt;td&gt;Map("key1" -&amp;gt; 1, "key2" -&amp;gt; 2, "key3" -&amp;gt; 3, "key4" to 1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Top Level Functions (Package Level)&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;&lt;a href="https://jducoeur.medium.com/finally-top-level-definitions-c67a33300a12"&gt;Will be supported in Scala 3&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extension Functions&lt;/td&gt;
&lt;td&gt;fun Any?.toString(): String { if (this == null) {return "null"} return toString()}&lt;/td&gt;
&lt;td&gt;extension (c: Circle) def circumference: Double = c.radius * math.Pi * 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operator Overloading&lt;/td&gt;
&lt;td&gt;with &lt;code&gt;operator infix&lt;/code&gt; keyword&lt;/td&gt;
&lt;td&gt;operators are just normal functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regex String&lt;/td&gt;
&lt;td&gt;"[0-9]".toRegex()&lt;/td&gt;
&lt;td&gt;"[0-9]".r&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tuple 2&lt;/td&gt;
&lt;td&gt;Pair(a, b)&lt;/td&gt;
&lt;td&gt;(a, b)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tuple 3&lt;/td&gt;
&lt;td&gt;Triple(a, b, c)&lt;/td&gt;
&lt;td&gt;(a, b, c)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Destructuring Assignment&lt;/td&gt;
&lt;td&gt;Objects with &lt;code&gt;componentN()&lt;/code&gt; (data classes and collections)&lt;/td&gt;
&lt;td&gt;Objects with &lt;code&gt;unapply()&lt;/code&gt; (extractors like case classes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tail Recursive Function&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tailrec&lt;/code&gt; keyword&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@tailrec&lt;/code&gt; annotation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple Inheritance Resolution&lt;/td&gt;
&lt;td&gt;Must override function in question manually&lt;/td&gt;
&lt;td&gt;Later trait wins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Class Inheritance&lt;/td&gt;
&lt;td&gt;only with &lt;code&gt;open&lt;/code&gt; or &lt;code&gt;abstract&lt;/code&gt; keyword&lt;/td&gt;
&lt;td&gt;allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The &lt;code&gt;sealed&lt;/code&gt; keyword&lt;/td&gt;
&lt;td&gt;sealed class is something like enum&lt;/td&gt;
&lt;td&gt;sealed types are confined in its source file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secondary/Auxiliary Constructors&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;constructor&lt;/code&gt; keyword&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;this()&lt;/code&gt; functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference Equality (the Java &lt;code&gt;==&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;===&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;eq&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Map Entry Literal&lt;/td&gt;
&lt;td&gt;k &lt;code&gt;to&lt;/code&gt; v&lt;/td&gt;
&lt;td&gt;k &lt;code&gt;-&amp;gt;&lt;/code&gt; v&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>kotlin</category>
      <category>scala</category>
    </item>
    <item>
      <title>Helm Charts, with or without Kustomize</title>
      <dc:creator>langyizhao</dc:creator>
      <pubDate>Thu, 22 Jul 2021 18:33:47 +0000</pubDate>
      <link>https://dev.to/langyizhao/helm-charts-with-or-without-kustomize-2f1j</link>
      <guid>https://dev.to/langyizhao/helm-charts-with-or-without-kustomize-2f1j</guid>
      <description>&lt;p&gt;I've recently read &lt;a href="https://jfrog.com/blog/power-up-helm-charts-using-kustomize-to-manage-kubernetes-deployments/" rel="noopener noreferrer"&gt;an interesting blog about using Helm together with Kustomize&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Though it provides good information such as the difference between Templates (via Helm) vs Overlays (via Kustomize), I would argue that, in a real deployment, the same effect can be achieved with Helm alone without the extra complexity of Kustomize.&lt;/p&gt;

&lt;p&gt;To avoid repeating the details in the original blog, I just provide the files to simulate the approach used by the original blog here: &lt;a href="https://github.com/langyizhao/helm-charts-with-or-without-kustomize/tree/master/with-kustomize" rel="noopener noreferrer"&gt;https://github.com/langyizhao/helm-charts-with-or-without-kustomize/tree/master/with-kustomize&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The distilled bare minimum steps are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;kustomize build&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;helm template&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl apply -k&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;3 steps are actually not too bad. The major clutter is the introduction of the temporary folder and temporary template files and the easily-confusing order of applying overlays.&lt;/p&gt;

&lt;p&gt;So how do we achieve the effect of overlays by just using templates? We will need some logic when drafting the template. Fortunately the Go template language under the hood of Helm charts easily support such trivial logic and some non-trivial ones.&lt;/p&gt;

&lt;p&gt;One possible implementation is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# from without-kustomize/templates/pod.yaml
{{- if and .Values.employeeName .Values.employeeDepartment }}
    args: ["/bin/echo My name is {{ .Values.employeeName }}. I work for {{ .Values.employeeDepartment }} department. Our company name is {{ .Values.companyName}}"]
{{ else }}
    args: ["/bin/echo Hello! My company name is {{ .Values.companyName }}"]
{{ end }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this case we will only render the complex form when the necessary values exists in the values.yaml file provided by our customer and safely default to the simple form when they are missing.&lt;/p&gt;

&lt;p&gt;No pre or post rendering needed and Helm alone handles everything.&lt;/p&gt;

&lt;p&gt;Feel free to check the simple examples out and try it yourself:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/langyizhao" rel="noopener noreferrer"&gt;
        langyizhao
      &lt;/a&gt; / &lt;a href="https://github.com/langyizhao/helm-charts-with-or-without-kustomize" rel="noopener noreferrer"&gt;
        helm-charts-with-or-without-kustomize
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;This is the example code for &lt;a href="https://dev.to/langyizhao/helm-charts-with-or-without-kustomize-2f1j" rel="nofollow"&gt;https://dev.to/langyizhao/helm-charts-with-or-without-kustomize-2f1j&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Example 1: &lt;code&gt;helm template without-kustomize -f values1.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Expected last line: &lt;code&gt;args: ["/bin/echo Hello! My company name is ABC Company"]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Example 2: &lt;code&gt;helm template without-kustomize -f values2.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Expected last line: &lt;code&gt;args: ["/bin/echo My name is Gary. I work for Marketing department. Our company name is ABC Company"]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;

  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/langyizhao/helm-charts-with-or-without-kustomize" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>helm</category>
      <category>kustomize</category>
    </item>
    <item>
      <title>Troubleshooting K8s Ingress Issues</title>
      <dc:creator>langyizhao</dc:creator>
      <pubDate>Tue, 01 Jun 2021 19:31:34 +0000</pubDate>
      <link>https://dev.to/langyizhao/troubleshooting-k8s-ingress-issues-3c8g</link>
      <guid>https://dev.to/langyizhao/troubleshooting-k8s-ingress-issues-3c8g</guid>
      <description>&lt;p&gt;Most K8s resource creation failures are easy to debug, usually you can figure them out with either &lt;code&gt;kubectl get&lt;/code&gt; or &lt;code&gt;kubectl describe&lt;/code&gt; command on the failed resource.&lt;/p&gt;

&lt;p&gt;However Ingress resources are often cluster-provider-specific, more often than not the errors are not explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  EKS Ingress Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;kubectl get ingress&lt;/code&gt; doesn't show the ingress you just created
&lt;/h3&gt;

&lt;p&gt;It might have been created in another namespace than you expected. Try again with &lt;code&gt;--all-namespaces&lt;/code&gt; flag.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;kubectl get ingress&lt;/code&gt; shows no ADDRESS after several minutes of resource creation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Try the AWS official example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.2.0/docs/examples/2048/2048_full.yaml
kubectl get ingress/ingress-2048 -n game-2048 --watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;If 1 works in a few minutes, the problem might be in your own manifest file.&lt;/li&gt;
&lt;li&gt;If no ADDRESS is assigned for 2048 either, try &lt;code&gt;kubectl logs -n kube-system deployment.apps/aws-load-balancer-controller&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If the error message is &lt;code&gt;Error from server (NotFound): deployments.apps "aws-load-balancer-controller" not found&lt;/code&gt;, follow &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html"&gt;https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html&lt;/a&gt; to deploy the controller.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Will add more contents for other providers later)&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html"&gt;https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>kubernetes</category>
      <category>eks</category>
      <category>k8s</category>
      <category>ingress</category>
    </item>
    <item>
      <title>K8s Ingress vs. OpenShift Route</title>
      <dc:creator>langyizhao</dc:creator>
      <pubDate>Fri, 26 Mar 2021 00:07:17 +0000</pubDate>
      <link>https://dev.to/langyizhao/k8s-ingress-vs-openshift-route-cmc</link>
      <guid>https://dev.to/langyizhao/k8s-ingress-vs-openshift-route-cmc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This article aims to clear some confusion between Ingress and Route, and hopefully enable you to take advantage of the power of both.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recently starting to deal with OpenShift clusters, I found most of the resource types in OCP are the native K8s resources I’m familiar with. Most of them, except for &lt;em&gt;Route&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ingress
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/"&gt;Ingress&lt;/a&gt; is the native API object K8s defined to enable external access into services in the cluster.&lt;/p&gt;

&lt;p&gt;It is THE resource type people usually expect to see in AKS, GKE, EKS, or in-house K8s installations when they connect their service to the vast internet.&lt;/p&gt;

&lt;p&gt;A bare Ingress resource YAML manifest is like an interface, where the actual behavior heavily depends on how it is provisioned in your cluster - more specifically, the &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/"&gt;Ingress Conroller&lt;/a&gt; backing it.&lt;/p&gt;

&lt;p&gt;For example, if your cluster uses &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html"&gt;ALB to back your Ingress&lt;/a&gt; (which is the most-likely case for AWS EKS), you will need some alb-specific annotations like this as part of the &lt;a href="https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.1.3/docs/examples/2048/2048_full.yaml"&gt;official example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally when you try to use Ingress you would want to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the Ingress Controller installed in your cluster.&lt;/li&gt;
&lt;li&gt;If none-installed, &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/"&gt;look up&lt;/a&gt; one that's supported by your cloud provider (including private/hybrid) and install it.&lt;/li&gt;
&lt;li&gt;Add the annotation based on the manual of that controller.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Route
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.openshift.com/container-platform/3.11/architecture/networking/routes.html"&gt;Route&lt;/a&gt;, on the other hand, is not a native K8s thing, it only exists in the OpenShift world.&lt;/p&gt;

&lt;p&gt;It depends on another Openshift concept - Router. Consider Router as plugins deployed on your cluster &lt;em&gt;nodes&lt;/em&gt; that enables configurable routings. By routings, I mean traffic from external clients to in-cluster application services.&lt;/p&gt;

&lt;p&gt;Note that a Router is installed on a node, so to reach the Router you need to reach the node first.&lt;/p&gt;

&lt;p&gt;For example, if an &lt;a href="https://docs.openshift.com/container-platform/3.11/architecture/networking/assembly_available_router_plugins.html#architecture-haproxy-router"&gt;HAProxy Router&lt;/a&gt; is used, external traffic is expected to go to the particular node hosting the HAProxy, then being routed to the service/pod.&lt;/p&gt;

&lt;p&gt;According to the &lt;a href="https://docs.openshift.com/container-platform/3.11/dev_guide/routes.html"&gt;dev guide&lt;/a&gt;, there are 3 ways to create a Route.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Openshift web console UI&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;oc&lt;/code&gt; CLI, such as &lt;code&gt;oc expose svc/frontend --hostname=www.example.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;YAML manifest, such as
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Route
metadata:
  name: frontend
spec:
  host: www.example.com
  path: "/test" 
  to:
    kind: Service
    name: frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like Ingress, Route also supports annotations, for example &lt;code&gt;router.openshift.io/cookie_name="my_cookie"&lt;/code&gt;. But note that the annotations have different prefixes than those of Ingress resources, thus their annotations are not interchangeable.&lt;/p&gt;

&lt;p&gt;However, the main method to control the behavior of a Route,  rather than through annotations, is by changing the &lt;a href="https://docs.openshift.com/container-platform/3.11/architecture/networking/routes.html#env-variables"&gt;Router Environment Variables&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ingress to Route
&lt;/h2&gt;

&lt;p&gt;Starting from Openshift 3.10, &lt;a href="https://www.openshift.com/blog/kubernetes-ingress-vs-openshift-route"&gt;Ingress objects created in Openshift can be translated into Route objects&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you know the difference between Ingress and routes well, this is very convenient.&lt;/p&gt;

&lt;p&gt;On the other hand, however, it can easily mislead people trying to take advantage of this translation.&lt;/p&gt;

&lt;p&gt;As described in the section above, Routes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Doesn't respect Ingress annotations. &lt;em&gt;As a result, your fine-tuned annotations on your Ingress manifest file would NOT affect the true behavior of the created Route.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Needs traffic to first reach the node. &lt;em&gt;So you will need to configure DNS records to Router nodes separately.&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;According to the &lt;a href="https://docs.openshift.com/container-platform/3.11/dev_guide/routes.html"&gt;dev guide&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DNS resolution for a host name is handled separately from routing; your administrator may have configured a cloud domain that will always correctly resolve to the OpenShift Container Platform router, or if using an unrelated host name you may need to modify its DNS records independently to resolve to the router.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This has to be taken into consideration and worked upon with the cluster admin for anyone familiar with K8s Ingress but not Openshift Route.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>openshift</category>
      <category>network</category>
    </item>
    <item>
      <title>Infrastructure as Code: the 5 Questions to Ask before You Start</title>
      <dc:creator>langyizhao</dc:creator>
      <pubDate>Mon, 15 Mar 2021 15:41:42 +0000</pubDate>
      <link>https://dev.to/langyizhao/infrastructure-as-code-the-5-questions-to-ask-before-you-start-1i0p</link>
      <guid>https://dev.to/langyizhao/infrastructure-as-code-the-5-questions-to-ask-before-you-start-1i0p</guid>
      <description>&lt;p&gt;According to Wikipedia, infrastructure as code (IaC) is the process of managing and provisioning computer data centers through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.&lt;/p&gt;

&lt;p&gt;Although I don’t think I can define it any better, I believe that “as code” implies slightly more than those definition files. Especially since over the years, we as developers have accumulated so many best practices and principles dealing with code, there is no reason we can’t apply those experiences to the infrastructure if we make it as code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 0: Should I consider Infrastructure as Code?
&lt;/h2&gt;

&lt;p&gt;Consider this a bonus question, but an important one before embarking on any path towards IaC. Let’s assume that if you are reading this article, you are either considering IaC or more likely than not, already starting your journey.&lt;/p&gt;

&lt;p&gt;Infrastructure as Code (IaC) is an inevitable phase of the DevOps movement. Automation is a cornerstone of DevOps culture [1], and after you finally automated your codebase with Version Control and CICD (or at least CI) pipelines, manual maneuvers of the underlying structure would feel so out of the place. People may call it with different names, like playbooks, cookbooks, manifests, and templates, but they are all the same as infrastructure code.&lt;/p&gt;

&lt;p&gt;One common objection to Infrastructure as Code (or perhaps any automation) is "We don’t make changes often enough to justify automating them" [2].&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2ru1gmcuqcpwtnr67r4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2ru1gmcuqcpwtnr67r4.png" alt="automation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Intuitively, it may feel true that changes happen much less often at the infrastructure level than at the code level.&lt;/p&gt;

&lt;p&gt;But wait a moment, have you considered configuration changes? How about security patches (like updating to the latest AMI if you are using AWS)? Scaling up your cluster before Black Friday? Have you ever restored your database from a snapshot?&lt;/p&gt;

&lt;p&gt;These are all changes related to infrastructure and can be made easier with IaC.&lt;/p&gt;

&lt;p&gt;Even when infrastructure changes are infrequent, there are many additional benefits of stack created via IaC. For example, it takes much less effort to fully control your resources (e.g. cleaning it up completely or spinning it up again later), thus ideal for any POC type of work, especially in cloud environments. I've seen teams unknowingly kept huge orphan EC2 and RDS instances running forever, contributing steady revenues to Amazon, only because they started them manually and lost the due observability very quickly.&lt;/p&gt;

&lt;p&gt;So from our perspective, the answer to whether you should consider IaC (even if you don’t adopt it) is most definitely yes.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Question 1: Infrastructure as Code or no Infrastructure at all (a.k.a. serverless)?
&lt;/h2&gt;

&lt;p&gt;It is beneficial to have your infrastructure as code. But sometimes less is more, and you don't even need your own infrastructure - your cloud provider takes care of it for you under Function-as-a-Service (FaaS), or serverless.&lt;/p&gt;

&lt;p&gt;I am a heavy user of AWS Lambda Functions because some tasks are so decoupled from other services that they are literally nothing but functions.&lt;/p&gt;

&lt;p&gt;A simple scheduled job to send out notifications to either humans or external systems? A good candidate for a serverless function. Of course, you can have a cron job in an EC2 instance but that would be crazy to have its own instance (a waste of resource and a burden for maintenance), and probably too coupled to have the instance shared with many other unrelated jobs.&lt;/p&gt;

&lt;p&gt;A filter to route important info via a webhook of your log aggregator to your Slack? Good for serverless too. You can write, test, and even deploy one in an hour and forget about it.&lt;/p&gt;

&lt;p&gt;A popular cloud-agnostic choice of tooling is the &lt;a href="https://github.com/serverless/serverless" rel="noopener noreferrer"&gt;Serverless Framework&lt;/a&gt;. Regarding languages, Go, Python, and Node.js all work very well. C#, Java (or JVM languages using the Java runtime) are not preferred for AWS Lambda because of the infamous cold-starts [3].&lt;/p&gt;

&lt;p&gt;My own rule of thumb is if I can handle a task with no more than 10 files of source code (excluding external libraries) in Python or Node.js, I would consider using FaaS. Avoid being too obsessed: The tendency of splitting services small enough to fit into functions can drive microservices into nano services, which is considered an anti-pattern by many [4].&lt;/p&gt;

&lt;p&gt;All being said, investing in serverless options for a subset of your services doesn't contradict the codification of your infrastructure in the big picture. You still can consider a not-so-standalone serverless function as a part of your infrastructure, connected with other parts of your system by API calls or streaming (SQS, Kinesis, Kafka, etc.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 2: To Terraform or not to Terraform?
&lt;/h2&gt;

&lt;p&gt;Among the Infrastructure as Code tools, Terraform popularity has undeniably grown in the last few years. Two of the four teams I most recently worked with were using Terraform as the primary tool (combining with other tools such as Kubernetes), with one other using plain CloudFormation and another completely going serverless. To decide whether Terraform is the right choice for your infrastructure, we can try to start with some comparisons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform vs. Cloud-specific Options
&lt;/h3&gt;

&lt;p&gt;Every major cloud provider invented their own template format that you can use to draft your infrastructure code such as ARM Template from Azure and CloudFormation from AWS.&lt;/p&gt;

&lt;p&gt;A very obvious advantage of using these formats is that no one can be more familiar with their cloud than the people developing them, thus you can expect that those templates reflect all of the latest cool features the cloud provider has added or is planning to add. If using cloud-agnostic options, you would sometimes have to wait for the community to come up with a solution to provision something only offered by a specific cloud provider. Tools with a larger community and ecosystem, like Terraform, would likely react faster than those with a smaller community.&lt;/p&gt;

&lt;p&gt;On the other hand, using the template from a certain cloud provider would inevitably result in vendor lock-in. You can't run your CloudFormation on GCP or Azure, and it is usually harder than it looks to translate among templates.&lt;/p&gt;

&lt;p&gt;Using cloud-agnostic tools like Terraform makes it theoretically easier to switch among cloud providers. Some companies run stacks on multi-cloud with intentional data redundancy in each cloud because, in reality, you can't escape vendor lock-in if that vendor holds all your data.&lt;/p&gt;

&lt;p&gt;Besides the concern of vendor lock-in, Terraform is also useful for the polycloud strategy, which is slightly different from multi-cloud. Polycloud implies you leverage components from different cloud providers in the same infrastructure stack. As an extreme case, you want a GCP Compute Engine instance to run some Azure Machine Learning task and save the result into AWS S3. Using Terraform with 3 providers configured is a much saner choice than writing one template for each cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform vs. Other Cloud-agnostic Options
&lt;/h3&gt;

&lt;p&gt;Excluding the cloud-specific options still leaves a lot of options out there. Big players including Chef, Puppet, and Ansible (though some may argue that they are more server configuration tools than infrastructure creating tools [2]), and my favorite is Kubernetes (commonly stylized as K8s).&lt;/p&gt;

&lt;p&gt;Kubernetes Is incredibly powerful and has an even larger ecosystem than Terraform. However, it might be unfair to compare them because Kubernetes is a container orchestration system that happens to meet the need of Infrastructure as Code and Terraform are scoped much narrowly.&lt;/p&gt;

&lt;p&gt;In Kubernetes, you define all resources in your infrastructure via manifest files (usually in the form of YAML), and the control plane manages them for you, almost magically. You need to know even fewer details about the underlying hardware than Terraform to provision new stacks, within an established K8s cluster. And it's much less likely to mess things up if role-based access control (RBAC) was configured correctly in that cluster.&lt;/p&gt;

&lt;p&gt;However setting up a Kubernetes cluster, especially for the first time, can be very hard. It would be easier if your cloud provider gives you managed options such as AWS EKS or GCP GKE, but still pretty involved to get it configured properly. &lt;/p&gt;

&lt;p&gt;OpenShift is a similar option to Kubernetes, and in fact, it is running K8s underneath and provides an extra abstraction layer. Some may find it useful, for me the vanilla K8s provides just the right level of abstraction. Yet another layer feels a little redundant and doesn't adjust the new moving parts introduced.&lt;/p&gt;

&lt;p&gt;Besides these established options there have also emerged many newer, smaller players that you may be interested in. &lt;a href="https://github.com/pulumi/pulumi" rel="noopener noreferrer"&gt;Pulumi&lt;/a&gt;, enables you to write your infrastructure code with the same languages you would usually use for your application code, such as Python, JS, TS, and Go, in case you are not a fan of the declarative DSL models used by most tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Pros and Cons of Terraform
&lt;/h3&gt;

&lt;p&gt;The module system is a major strength of Terraform that doesn't exist in many cloud-agnostic or cloud-specific options natively. Not only it dramatically increases the reusability of your infrastructure code, but you also get the invaluable opportunity to distill the difference between the different environments in just a couple of files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── modules
│   ├── backend
│   │   ├── main.tf
│   │   ├── user_data.sh
│   │   └── variables.tf
│   ├── documentDB
│   │   ├── main.tf
│   │   └── variables.tf
│   ├── frontend
│   │   ├── install_docker_compose.sh
│   │   ├── main.tf
│   │   ├── routings.tf
│   │   └── variables.tf
│   ├── grafana
│   │   ├── main.tf
│   │   └── variables.tf
│   ├── postgreSQL
│   │   ├── main.tf
│   │   └── variables.tf
│   └── redis
│       ├── main.tf
│       └── variables.tf
├── production
│   ├── main.tf
│   └── variables.tf
├── qa
│   ├── main.tf
│   └── variables.tf
└── staging
    ├── main.tf
    └── variables.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, all the differences in configuration between each environment are strictly scoped in the stack level &lt;code&gt;variables.tf&lt;/code&gt; files, and they would be very concise if your module-level &lt;code&gt;variables.tf&lt;/code&gt; files have sensible defaults.&lt;/p&gt;

&lt;p&gt;The biggest gripe about working with Terraform is the fragility of its "state file", which is &lt;code&gt;terraform.tfstate&lt;/code&gt; by default. It is understandable that a state must be persisted somewhere to manage any dynamic infrastructure, but many tools abstract the trouble away from you. For example, CloudFormation provides drift detection as a service, through the console or API, and Kubernetes strives to be as stateless as possible.&lt;/p&gt;

&lt;p&gt;Terraform leaves the duty of safekeeping the state of the stack to you, the applier of the infrastructure code. There are a few different ways of managing the state file, but the last thing you would want to do is to keep it publicly in your repo because anyone can open the file with a text editor and peek at the plaintext secrets inside. For AWS environments consider using the "s3" backend to store the state file. A properly secured private S3 bucket is required and a DynamoDB table is used for locking (the same bucket and lock table can be used for multiple stacks).&lt;/p&gt;

&lt;p&gt;I highly recommend enabling the versioning feature on the cloud storage service containing your state file so you can restore your corrupted state file from the last working version. If you can't enable it or you store your state file with a local backend, you may want to back up the state file before applying anything nontrivial.&lt;/p&gt;

&lt;p&gt;Another not-so-obvious issue of Terraform is the version compatibility. Terraform is not even 1.0 at the time of writing, which is more than 6 years after its initial release. Being sub-1.0, on the bright side, implies it's still rapidly evolving, but meanwhile, this means each version could break backward-compatibility and get forgiven. Hashicorp does provide you helper commands or tools to migrate, but from my experience upgrading many stacks either from 0.11 to 0.12 or 0.12 to 0.13, there is always a chance to miss something and corrupt your state file. Again, do keep a backup of your state file! For Kubernetes, I've had much fewer issues when it upgraded minor versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 3: When or how frequently should I apply my IaC changes?
&lt;/h2&gt;

&lt;p&gt;After you finish coding your infrastructure, you will need to apply it to the real world to have your stack instantiated. You can choose the way to apply based on the requirements of how soon and how often changes will be made. &lt;/p&gt;

&lt;p&gt;The fastest way to create your infrastructure from code or apply changes is to run it manually on CLI. Usually, the only other thing you need is the right access from your cloud provider. For AWS, it could be an STS token to assume an admin role or an ID/secret pair in the &lt;code&gt;.aws&lt;/code&gt; folder or as environment variables.&lt;/p&gt;

&lt;p&gt;If the idea of creating stacks directly from your laptop scares you or your security team, you can run the same commands after SSHing into a dedicated host with preset system roles just enough for managing your piece of infrastructure. This manual approach gives you more flexibility in the timing of applying stack changes, with the drawback of noncompliance in many companies, unless it's just a POC project.&lt;/p&gt;

&lt;p&gt;A more widely accepted approach is to embed your infrastructure change into a CI pipeline. There are lots of plugins pairing CI platforms with IaC tools such as &lt;a href="https://plugins.jenkins.io/terraform/" rel="noopener noreferrer"&gt;the Terraform Plugin on Jenkins&lt;/a&gt;. But more often than not, you don't even need any plugin to apply your infrastructure code in your CI. In Gitlab CI, for example, I only need to set the job image as &lt;code&gt;hashicorp/terraform&lt;/code&gt; with the image tag matching my script to run any Terraform commands I would usually run in my CLI.&lt;/p&gt;

&lt;p&gt;There are also other ways to apply your changes with third-party tools. &lt;a href="https://github.com/runatlantis/atlantis" rel="noopener noreferrer"&gt;Atlantis&lt;/a&gt;, for example, applies your changes when a Pull Request containing changes in Terraform files is submitted into Gitlab. Using the Github Pull Request page as the main interaction point is an increasingly popular choice for many modern tools (e.g. the static code analysis platform &lt;a href="https://www.muse.dev/" rel="noopener noreferrer"&gt;MuseDev&lt;/a&gt;) because it is one of the few points in the development lifecycle that draws the attention of the entire team.&lt;/p&gt;

&lt;p&gt;Regardless of your choice, there is always the risk to build your stack into something monolithic, which slows you down in the long run. It is almost always helpful to make your changes small, modular, and independent of each other. This is especially true if you agree with the "Treat your servers like cattle, not pets" mindset [5], which means you should have the majority of your system disposable and reproducible.&lt;/p&gt;

&lt;p&gt;For example, if you use Terraform, as we discussed above, the concept of modules would be your friend. You may want to start creating modules early and keep your root level main.tf file as small as possible: Ideally only a set of module blocks beside the mandatory terraform and provider blocks. Moreover, considering the risk of the state file corruption mentioned earlier, you may want to avoid having too many modules in the same stack sharing the same &lt;code&gt;tfstate&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Want to be even more confident to apply your change as frequently as you want? Consider testing your Infrastructure code, which is the next question to ask.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 4: How to Test my Infrastructure Code?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fy7Hm9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fy7Hm9.jpg" alt="Test in Production"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you catch a colleague testing his code in production, will you recall this famous "I test in production" meme and laugh at him?&lt;/p&gt;

&lt;p&gt;Well, how about when his code is in the context of "Infrastructure as Code"? Will your reaction change to "Oh, testing THAT in production is OK."? But is the infrastructure code really so different from the application code we are familiar with: that it is not testable in lower environments?&lt;/p&gt;

&lt;p&gt;To answer the question let's first admit that infrastructure code IS harder to test. For one thing, you can hardly create a miniature version of the full infrastructure stack in your laptop, thus local testing is not always feasible. For another, mocking an upstream infrastructure is much harder than mocking an upstream service like in your application code because of the difference in the level of abstraction.&lt;/p&gt;

&lt;p&gt;Fortunately, being unable to test something locally doesn't mean you have to test it in production. You should still have at least one other environment lower than production, whether you call it testing, QA, staging, or something else. Deploying a testing environment is a test itself, for your infrastructure code.&lt;/p&gt;

&lt;p&gt;Assertions make tests possible, and for each IaC tool, there are companion tools to help you verify the actual end state of an infrastructure change against the desired. For Terraform, there is &lt;a href="https://github.com/gruntwork-io/terratest" rel="noopener noreferrer"&gt;terratest&lt;/a&gt;, for CloudFormation there is &lt;a href="https://github.com/aws-quickstart/taskcat" rel="noopener noreferrer"&gt;taskcat&lt;/a&gt;, and &lt;a href="https://github.com/inspec/inspec" rel="noopener noreferrer"&gt;inspec&lt;/a&gt; is for Chef. Even if you don't use these assertion tools, simply running your integration tests prepared for the application code would many expose potential problems in your infrastructure code. If you use CICD to apply your infrastructure changes, put the pipeline steps of applying changes to lower environment AND integration testing before the step to change production infrastructure.&lt;/p&gt;

&lt;p&gt;However, testing and assertion in a lower environment only make sense when you run the same infrastructure code for your production environment. Take some time to modularize and reuse the infrastructure code you share among environments instead of copy/paste them around.&lt;/p&gt;

&lt;p&gt;Sometimes, instead of full-fledged assertive testing, static code analysis could be a much more pragmatic target to automate. And yes, you can do static code analysis on your infrastructure. Most IaC tools included CLI commands to validate and lint your infrastructure code out of the box, and third-party tools can go beyond that and find certain misconfigurations and security-related issues as well. Below is an example of &lt;a href="https://github.com/bridgecrewio/checkov" rel="noopener noreferrer"&gt;checkov&lt;/a&gt; scanning an IaC stack coded with Terraform, triggered via &lt;a href="https://www.muse.dev/" rel="noopener noreferrer"&gt;MuseDev&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0myd4tgyc2qvh24i076s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0myd4tgyc2qvh24i076s.png" alt="Checkov"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 5: Will IaC mitigate my Tech Debt?
&lt;/h2&gt;

&lt;p&gt;Infrastructure as Code, by itself, is just a tool like the Cloud or the DevOps or the AI, will not magically solve your problem. You have to decide if it is the right tool for your particular fix.&lt;/p&gt;

&lt;p&gt;We usually consider technical debt as a combination of design debt and code debt [6], but here let's take either level apart and evaluate their relationships with IaC:&lt;/p&gt;

&lt;h3&gt;
  
  
  IaC and Design Debt
&lt;/h3&gt;

&lt;p&gt;Here we limit the term "design" at the architectural level, rather than the application level.&lt;/p&gt;

&lt;p&gt;Although in an ideal world a good architect should defer all the decisions at the infrastructure level as long as possible [7] to avoid premature constraints, the rubber has to meet the road eventually. To materialize the system, you have to decide on the exact type of DB, queue, server, logging, monitoring, alerting, and everything that you initially abstracted away from the developers of the application code. And some of the decisions are bound to be wrong the first time however experienced you are, because of the lack of information, which would be collected only after the initial decisions are made.&lt;/p&gt;

&lt;p&gt;You will want to be able to refactor your infrastructure, continuously in some cases, after you start to get more information. You will want to be agile. And this is when you reap the benefits of Infrastructure as Code.&lt;/p&gt;

&lt;p&gt;In places where IaC was not all adopted or implemented incompletely as an afterthought, I've seen infrastructure such as application servers drifted from their original state so much that no one dares to make changes on them. They are called by some "snowflake systems" (don't confuse with Snowflake Data Warehouse) because they are so unique that no one can reproduce them [2]. With the existence of such systems, any attempt to refactor your code would either fail or get dramatically slowed down, falling into the automation fear spiral [8].&lt;/p&gt;

&lt;p&gt;Contrarily, proper implementation of IaC would result in disposable and replaceable modules of the infrastructure that you can quickly troubleshoot and resolve failures. The effort and risk of swapping new components in and old ones out would be finally recused to a level that you can experiment and refactor the details of your architectural design. And this is how IaC helps you solve your tech debt.&lt;/p&gt;

&lt;h3&gt;
  
  
  IaC and Code Debt
&lt;/h3&gt;

&lt;p&gt;When you talk about spaghetti, smelly, inflexible or legacy code, you know you are talking about the code debt type of tech debt.&lt;/p&gt;

&lt;p&gt;Unfortunately, Infrastructure as Code, however good it is, will not help you refactor your application code. In fact, these two types of code shouldn't even know the details of each other.&lt;/p&gt;

&lt;p&gt;Ideally, thanks to the power of the cloud and containerization, your application layer should be decoupled from the runtime platform hosting it, and the runtime platform should be even further decoupled from the infrastructure platform supporting it. Your application code and infrastructure code should be in parallel dimensions.&lt;/p&gt;

&lt;p&gt;As a result, You still need your good old red/green/refactor cycles to gradually improve the quality of your application code. Even more, you may want to start refactoring your infrastructure code as well from now on, since they are not only "real" code, but we also have ways to test them (see Question 4).&lt;/p&gt;

&lt;p&gt;Fortunately, nowadays we have plenty of tools to help us fight code debt. For example, static code analysis tools with properly configured ruleset could easily give you actionable refactoring suggestions for source code of almost any language [9], and modern Continuous Assurance&lt;br&gt;
 platforms such as &lt;a href="https://www.muse.dev/" rel="noopener noreferrer"&gt;MuseDev&lt;/a&gt; are all you need to integrate those tools into your own repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary or TLDR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Q0: Should I consider Infrastructure as Code?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suggestion: Yes if you have a cloud environment, public, hybrid or private.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q1: Infrastructure as Code or Serverless?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suggestion: For small standalone services, try serverless. For complex architecture, IaC or both.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q2: To Terraform or not to Terraform?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suggestion: Use Terraform if you worry about vendor lock-in. Be aware of other options (such as K8S) if you worry about getting locked into Terraform itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q3: When or how frequently should I apply my IaC changes?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suggestion: The smaller the unit of your infrastructure stack is, the more frequent you can change it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q4: How to Test my Infrastructure Code?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suggestion: Lint your infrastructure code before applying your changes. Optionally use assertions to verify the deployment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Q5: Will IaC mitigate my Tech Debt?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Suggestion: IaC helps you fixing your design debt, but you need other tools to fix your code debt.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[1] &lt;a href="https://martinfowler.com/bliki/DevOpsCulture.html" rel="noopener noreferrer"&gt;DevOpsCulture&lt;/a&gt;&lt;br&gt;
[2] &lt;a href="https://books.google.com/books/about/Infrastructure_as_Code_2nd_Edition.html?id=VYtAzQEACAAJ" rel="noopener noreferrer"&gt;Infrastructure as Code, 2nd Edition - Kief Morris&lt;/a&gt; &lt;br&gt;
[3] &lt;a href="https://aws.amazon.com/blogs/compute/new-for-aws-lambda-predictable-start-up-times-with-provisioned-concurrency/" rel="noopener noreferrer"&gt;New for AWS Lambda – Predictable start-up times with Provisioned Concurrency | AWS Compute Blog&lt;/a&gt;&lt;br&gt;
[4] &lt;a href="https://dzone.com/articles/microservices-nanoservices-teraservices-and-server-1#" rel="noopener noreferrer"&gt;Microservices, Nanoservices, Teraservices, and Serverless - DZone Microservices&lt;/a&gt;&lt;br&gt;
[5] &lt;a href="http://cloudscaling.com/blog/cloud-computing/the-history-of-pets-vs-cattle/" rel="noopener noreferrer"&gt;The History of Pets vs Cattle and How to Use the Analogy Properly | Cloudscaling&lt;/a&gt;&lt;br&gt;
[6] &lt;a href="https://en.wikipedia.org/wiki/Technical_debt" rel="noopener noreferrer"&gt;Technical debt - Wikipedia&lt;/a&gt;&lt;br&gt;
[7] &lt;a href="https://blog.cleancoder.com/uncle-bob/2016/01/04/ALittleArchitecture.html" rel="noopener noreferrer"&gt;A Little Architecture&lt;/a&gt;&lt;br&gt;
[8] &lt;a href="https://www.thoughtworks.com/insights/blog/infrastructure-code-automation-fear-spiral" rel="noopener noreferrer"&gt;Infrastructure as Code: The Automation Fear Spiral | ThoughtWorks&lt;/a&gt;&lt;br&gt;
[9] &lt;a href="https://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis" rel="noopener noreferrer"&gt;List of tools for static code analysis - Wikipedia&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My 3 Different Attempts in Creating an EKS K8s Cluster</title>
      <dc:creator>langyizhao</dc:creator>
      <pubDate>Mon, 15 Mar 2021 14:39:36 +0000</pubDate>
      <link>https://dev.to/langyizhao/my-3-different-attempts-in-creating-an-eks-k8s-cluster-klk</link>
      <guid>https://dev.to/langyizhao/my-3-different-attempts-in-creating-an-eks-k8s-cluster-klk</guid>
      <description>&lt;p&gt;For the past few years, I was just &lt;em&gt;using&lt;/em&gt; Kubernetes. Only until recently, I had to do some experimental work in a sandboxed Kubernetes environment. The first thing I need to do is to &lt;em&gt;build&lt;/em&gt; the sandbox myself.&lt;/p&gt;

&lt;p&gt;There was no hard requirement about how to build it, but since our team was already using AWS, EKS is the obvious choice at least to me: Rather than rolling my own I almost always prefer to use a managed service so I don't have to worry about the maintenance, some of the testing, and most of the security issues. &lt;/p&gt;

&lt;p&gt;For me, the trade-offs such as vendor lock-in and marginally more costs are acceptable.&lt;/p&gt;

&lt;p&gt;A consideration after deciding to use EKS is whether to use Fargate to back the nodes or the plain auto-scaling EC2 instances. Fargate is attractive to me because of its serverless vibe: I won't need the POC to be up all day long, so on-demand is not bad. But again, this is a soft requirement because I would only need a few micro to small nodes thus the cost would be negligible.&lt;/p&gt;

&lt;p&gt;[Edit] Eventually I went back to plain EC2 from Fargate because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fargate requires more steps to set up in some of the cluster building options I list below.&lt;/li&gt;
&lt;li&gt;Fargate requires more steps to add additional controllers (such as the AWS Load Balancer Controller ) into an established cluster.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without further ado, here are the three ways I experimented in creating a new EKS cluster:&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment 1: Terraform with official AWS resources types
&lt;/h2&gt;

&lt;p&gt;When using Terraform, my usual preference is to use as many official resources as possible before resorting to 3rd-party modules.&lt;/p&gt;

&lt;p&gt;For EKS, I noticed the official AWS resource is &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster"&gt;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created a local module starting from this &lt;code&gt;aws_eks_cluster&lt;/code&gt; resource:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_eks_cluster" "fargate-eks-cluster" {
  name     = "fargate-eks-cluster-${var.env}"
  role_arn = aws_iam_role.cluster-role.arn

  # Refer to https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster#basic-usage
  ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I realized it depends on a few other resources such as &lt;code&gt;aws_iam_role&lt;/code&gt; and &lt;code&gt;aws_iam_role_policy_attachment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Fortunately, I can find the basic examples in the links above.&lt;/p&gt;

&lt;p&gt;Trying to use Fargate, I referred to &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_fargate_profile"&gt;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_fargate_profile&lt;/a&gt; and created three Fargate profiles for the default namespace, our working namespace and one specifically for CoreDNS as instructed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_eks_fargate_profile" "fargate-profile-default-ns" {
  cluster_name           = aws_eks_cluster.fargate-eks-cluster.name
  fargate_profile_name   = "fargate-profile-default-ns-${var.env}"
  pod_execution_role_arn = aws_iam_role.fargate-role.arn
  subnet_ids             = var.private_subnets

  selector {
    namespace = "default"
  }
}

resource "aws_eks_fargate_profile" "fargate-profile-coredns" {
  cluster_name           = aws_eks_cluster.fargate-eks-cluster.name
  fargate_profile_name   = "fargate-profile-coredns-${var.env}"
  pod_execution_role_arn = aws_iam_role.fargate-role.arn
  subnet_ids             = var.private_subnets

  selector {
    namespace = "kube-system"
    labels    = { "k8s-app": "kube-dns" }
  }
}

resource "aws_eks_fargate_profile" "fargate-profile-muse" {
  cluster_name           = aws_eks_cluster.fargate-eks-cluster.name
  fargate_profile_name   = "fargate-profile-muse-${var.env}"
  pod_execution_role_arn = aws_iam_role.fargate-role.arn
  subnet_ids             = var.private_subnets

  selector {
    namespace = "muse"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I created the &lt;code&gt;aws_iam_role&lt;/code&gt; resource for all of them.&lt;/p&gt;

&lt;p&gt;And these are all the resources I needed in this local module. I used this module in my root module and did &lt;code&gt;terraform apply&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Terraform steps looked successful and after the cluster creation, I was able to verify that &lt;code&gt;kubectl&lt;/code&gt; commands do connect to the right server.&lt;/p&gt;

&lt;p&gt;However, when I tried to create K8s resources with my pre-existing manifest files, it didn't work as expected: the Overview Tab in the AWS console didn't show anything node alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment 2: With &lt;code&gt;eksctl&lt;/code&gt; CLI commands
&lt;/h2&gt;

&lt;p&gt;I was initially following the official &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-eksctl.html"&gt;Getting started with eksctl&lt;/a&gt; guide in creating my cluster, with the &lt;code&gt;--fargate&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;At the end of the &lt;code&gt;eksctl create cluster --fargate&lt;/code&gt; command, a Fargate profile was created and several configurations were done under the hood. This is at least a couple of steps ahead of what I have achieved at the end of experiment 1.&lt;/p&gt;

&lt;p&gt;Unfortunately, the out-of-box Fargate profile apparently doesn't work for non-default namespaces, and the networking wasn't quite right.&lt;/p&gt;

&lt;p&gt;Despite [following the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/troubleshooting.html#worker-node-fail"&gt;troubleshooting steps&lt;/a&gt; as well as &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/fargate-profile.html"&gt;creating custom Fargate Profiles&lt;/a&gt;, I still couldn't get any of my testing pods into running status. I believe I wasn't far from getting everything working but decided to try something else with the remainder of time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiment 3: Experiment 3: Terraform with community modules
&lt;/h2&gt;

&lt;p&gt;In seek of a more turnkey-ish solution, I looked into this community Terraform EKS module: &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks"&gt;https://github.com/terraform-aws-modules/terraform-aws-eks&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As mentioned in its &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks/issues/635"&gt;own issue&lt;/a&gt;, the complexity of this module is getting very high. I would usually avoid any heavy module like this and stay with plain resources if I hadn't failed in Experiment 1.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;main.tf&lt;/code&gt; file was just a combination of its &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples"&gt;working examples&lt;/a&gt; especially &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples/basic"&gt;https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples/basic&lt;/a&gt;, except for that the module source has to be&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module "eks" {
  source          = "terraform-aws-modules/eks/aws"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of the &lt;code&gt;../..&lt;/code&gt; in the example.&lt;/p&gt;

&lt;p&gt;The end result turned out to be really good and the generated cluster met all our needs for my sandbox (Though I still had to install &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/aws-load-balancer-controller.html"&gt;AWS Load Balancer Controller&lt;/a&gt; separately for Ingress)&lt;/p&gt;

&lt;h2&gt;
  
  
  My Conclusion
&lt;/h2&gt;

&lt;p&gt;As it turned out, my smoothest cluster creating experience was to use the community &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks"&gt;Terraform EKS module&lt;/a&gt; following its &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples"&gt;examples&lt;/a&gt;. It works almost out-of-the-box.&lt;/p&gt;

&lt;p&gt;If Terraform is not your thing, using &lt;code&gt;eksctl&lt;/code&gt; would also save you a lot of initial legwork by creating the default underlying resources behind the scene with its subcommand. Just keep in mind that you still need to tinker with the cluster after the creation is done.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>eks</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
