<?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: Joaquin Menchaca</title>
    <description>The latest articles on DEV Community by Joaquin Menchaca (@joachim8675309).</description>
    <link>https://dev.to/joachim8675309</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%2F8758%2F1U3OJ6pH.jpg</url>
      <title>DEV Community: Joaquin Menchaca</title>
      <link>https://dev.to/joachim8675309</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joachim8675309"/>
    <language>en</language>
    <item>
      <title>Essential DevOps Tools for Ubuntu</title>
      <dc:creator>Joaquin Menchaca</dc:creator>
      <pubDate>Wed, 14 Jan 2026 20:25:54 +0000</pubDate>
      <link>https://dev.to/joachim8675309/essential-devops-tools-for-ubuntu-5421</link>
      <guid>https://dev.to/joachim8675309/essential-devops-tools-for-ubuntu-5421</guid>
      <description>&lt;p&gt;Popular tools for provisioning the cloud are &lt;a href="https://developer.hashicorp.com/terraform" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; and &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; tools &lt;code&gt;kubectl&lt;/code&gt; and &lt;code&gt;helm&lt;/code&gt;. For Linux, online instructions for how to install these tools can be inconsistent and potentially error prone. This article shows how to install these tools on &lt;a href="https://www.debian.org/" rel="noopener noreferrer"&gt;Debian&lt;/a&gt; and &lt;a href="https://ubuntu.com/download/server" rel="noopener noreferrer"&gt;Ubuntu&lt;/a&gt; based distros, which by extension would include &lt;a href="https://linuxmint.com/" rel="noopener noreferrer"&gt;Mint&lt;/a&gt;, &lt;a href="https://system76.com/pop/" rel="noopener noreferrer"&gt;Pop! OS&lt;/a&gt;, &lt;a href="https://zorin.com/os/" rel="noopener noreferrer"&gt;Zorin OS&lt;/a&gt; and others.&lt;/p&gt;

&lt;p&gt;This guide walk you through how to install the latest versions of popular DevOps tool on Ubuntu Linux. This was tested on &lt;a href="https://releases.ubuntu.com/noble/" rel="noopener noreferrer"&gt;Ubuntu 24.04 Noble Nambat&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Segue: Why Linux?
&lt;/h2&gt;

&lt;p&gt;For developers accustomed to &lt;strong&gt;macOS&lt;/strong&gt; or &lt;strong&gt;Windows&lt;/strong&gt;, choosing &lt;strong&gt;Linux&lt;/strong&gt; as a primary development platform may seem unusual. For others, &lt;strong&gt;Linux&lt;/strong&gt; is the default choice. With &lt;strong&gt;Windows&lt;/strong&gt; now supporting &lt;strong&gt;Linux&lt;/strong&gt; through &lt;strong&gt;WSL&lt;/strong&gt;, Linux-based development environments have become increasingly common.&lt;/p&gt;

&lt;p&gt;Beyond personal preference, the strongest case for &lt;strong&gt;Linux&lt;/strong&gt; is environment consistency. Production systems, and especially CI/CD pipelines, almost always run on &lt;strong&gt;Linux&lt;/strong&gt;. Developing and testing directly in a &lt;strong&gt;Linux&lt;/strong&gt; environment allows you to validate build, test, and deployment scripts under the same conditions they'll run in production.&lt;/p&gt;

&lt;p&gt;This consistency shortens development cycles by reducing surprises late in the pipeline and eliminates platform-specific "gotchas" that exist on &lt;strong&gt;macOS&lt;/strong&gt; or &lt;strong&gt;Windows&lt;/strong&gt; but never appear in Linux-based CI/CD or production systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tools
&lt;/h2&gt;

&lt;p&gt;This is an overview of the tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cloud Provisioning&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/terraform" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; [&lt;code&gt;terraform&lt;/code&gt;]: tool for provisioning cloud infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; [&lt;code&gt;aws&lt;/code&gt;]: tool to interact with Amazon Web Services&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/okta/okta-aws-cli" rel="noopener noreferrer"&gt;okta-aws-cli&lt;/a&gt; [&lt;code&gt;okta-aws-cli&lt;/code&gt;]: allows you to get temporary IAM credentials using Okta as the Identity provider.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/cli/azure/" rel="noopener noreferrer"&gt;Azure CLI Tools&lt;/a&gt; [&lt;code&gt;az&lt;/code&gt;]: tool to interact with Azure&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.cloud.google.com/sdk/docs/install-sdk" rel="noopener noreferrer"&gt;Google Cloud CLI Tools&lt;/a&gt; [&lt;code&gt;gcloud&lt;/code&gt;]: tool to interact with GCP&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Containers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;docker&lt;/a&gt; [&lt;code&gt;docker&lt;/code&gt;]: tools to build container images and run containers &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/reference/kubectl/" rel="noopener noreferrer"&gt;Kubernetes CLI&lt;/a&gt; [&lt;code&gt;kubectl&lt;/code&gt;]: command line tool for interacting with Kubernetes control plan&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; [&lt;code&gt;helm&lt;/code&gt;]: Tool for configuring, installing, and distributing Kubernetes applications.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kustomize.io/" rel="noopener noreferrer"&gt;Kustomize&lt;/a&gt; [&lt;code&gt;kustomize&lt;/code&gt;]: tool to configure Kubernetes application through patching.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://helmfile.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Helmfile&lt;/a&gt; [&lt;code&gt;helmfile&lt;/code&gt;]: is a declarative spec for deploying helm charts that allows you to template helm chart values as well integrate patching support&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://krew.sigs.k8s.io/" rel="noopener noreferrer"&gt;Krew&lt;/a&gt; [&lt;code&gt;kubectl krew&lt;/code&gt;]: is a plugin system for Kubernetes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/corretto/" rel="noopener noreferrer"&gt;Correto OpenJDK&lt;/a&gt; [&lt;code&gt;java&lt;/code&gt;, &lt;code&gt;javac&lt;/code&gt;, &lt;code&gt;jar&lt;/code&gt;, &lt;code&gt;keytool&lt;/code&gt;]: Corretto is an OpenJDK distribution that is supported on many platforms.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Others&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/vault" rel="noopener noreferrer"&gt;Vault&lt;/a&gt; [vault]: Allow securing, storing, and controlling access to secrets artifacts: tokens, passwords, certificates, and encryption keys.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Installation
&lt;/h2&gt;

&lt;p&gt;Below are script steps that you can use to install the packages and tools. These scripts follow the &lt;a href="https://google.github.io/styleguide/shellguide.html" rel="noopener noreferrer"&gt;Google Shell Style Guide&lt;/a&gt; and I took some measures to reduce the width so that it would be nicely in this guide.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repositories
&lt;/h3&gt;

&lt;p&gt;Many of these tools are available from private repositories. You can add them with the following script below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt update

  &lt;span class="c"&gt;# Hashicorp&lt;/span&gt;
  &lt;span class="c"&gt;# Uses Ubuntu codename dynamically&lt;/span&gt;
  &lt;span class="nv"&gt;UBUNTU_CODENAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oP&lt;/span&gt; &lt;span class="s1"&gt;'(?&amp;lt;=UBUNTU_CODENAME=).*'&lt;/span&gt; /etc/os-release&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;# terraform, vault&lt;/span&gt;
  &lt;span class="c"&gt;# https://developer.hashicorp.com/vault/install#linux&lt;/span&gt;
  &lt;span class="c"&gt;# https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli&lt;/span&gt;
  add_apt_repo &lt;span class="s2"&gt;"hashicorp"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://apt.releases.hashicorp.com/gpg"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://apt.releases.hashicorp.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$UBUNTU_CODENAME&lt;/span&gt;&lt;span class="s2"&gt; main"&lt;/span&gt;

  &lt;span class="c"&gt;# kubectl&lt;/span&gt;
  &lt;span class="c"&gt;# https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-using-native-package-management&lt;/span&gt;
  add_apt_repo &lt;span class="s2"&gt;"kubernetes"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://pkgs.k8s.io/core:/stable:/v1.35/deb/"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"/"&lt;/span&gt;

  &lt;span class="c"&gt;# helm&lt;/span&gt;
  &lt;span class="c"&gt;# https://helm.sh/docs/intro/install/#from-apt-debianubuntu&lt;/span&gt;
  add_apt_repo &lt;span class="s2"&gt;"helm"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://packages.buildkite.com/helm-linux/helm-debian/gpgkey"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://packages.buildkite.com/helm-linux/helm-debian/any/"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"any main"&lt;/span&gt;

  &lt;span class="c"&gt;# Corretto&lt;/span&gt;
  &lt;span class="c"&gt;# https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/generic-linux-install.html&lt;/span&gt;
  add_apt_repo &lt;span class="s2"&gt;"corretto"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://apt.corretto.aws/corretto.key"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://apt.corretto.aws"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"stable main"&lt;/span&gt;

  &lt;span class="c"&gt;# google-cloud-cli&lt;/span&gt;
  &lt;span class="c"&gt;# https://docs.cloud.google.com/sdk/docs/install-sdk#deb&lt;/span&gt;
  add_apt_repo &lt;span class="s2"&gt;"googlecloud"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://packages.cloud.google.com/apt/doc/apt-key.gpg"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://packages.cloud.google.com/apt"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"cloud-sdk main"&lt;/span&gt;

  &lt;span class="c"&gt;# azure-cli&lt;/span&gt;
  &lt;span class="c"&gt;# https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-linux?view=azure-cli-latest&amp;amp;pivots=apt&lt;/span&gt;
  add_apt_repo &lt;span class="s2"&gt;"azure"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://packages.microsoft.com/keys/microsoft.asc"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://packages.microsoft.com/repos/azure-cli/"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$UBUNTU_CODENAME&lt;/span&gt;&lt;span class="s2"&gt; main"&lt;/span&gt;

  &lt;span class="c"&gt;# docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin&lt;/span&gt;
  &lt;span class="c"&gt;# Docs: https://docs.docker.com/engine/install/ubuntu/&lt;/span&gt;
  add_apt_repo &lt;span class="s2"&gt;"docker"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://download.docker.com/linux/ubuntu/gpg"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"https://download.docker.com/linux/ubuntu"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
               &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$UBUNTU_CODENAME&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

add_apt_repo&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;KEY_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt; &lt;span class="c"&gt;# Signed-By&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;REPO_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$3&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;DISTRO_STRING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$4&lt;/span&gt; &lt;span class="c"&gt;# "Suites Components" or "/"&lt;/span&gt;

  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;KEYRING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/usr/share/keyrings/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-archive-keyring.gpg"&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;LIST_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/etc/apt/sources.list.d/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.list"&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Configuring repository: &lt;/span&gt;&lt;span class="nv"&gt;$NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="c"&gt;# Download and dearmor the GPG key&lt;/span&gt;
  wget &lt;span class="nt"&gt;-qO&lt;/span&gt; - &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEY_URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;--yes&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEYRING&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="c"&gt;# Construct and save the list file&lt;/span&gt;
  &lt;span class="c"&gt;# Note: arch=$ARCH is included by default &lt;/span&gt;
  &lt;span class="c"&gt;#       as it is standard for most 3rd party repos&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt; signed-by=&lt;/span&gt;&lt;span class="nv"&gt;$KEYRING&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="nv"&gt;$REPO_URI&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DISTRO_STRING&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LIST_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null

  &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-o&lt;/span&gt; Dir::Etc::sourcelist&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LIST_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-o&lt;/span&gt; Dir::Etc::sourceparts&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-o&lt;/span&gt; APT::Get::List-Cleanup&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tools Installed from Repositories
&lt;/h3&gt;

&lt;p&gt;For the tools that can be installed from these repositories, we can run through the following script below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 apt-transport-https &lt;span class="se"&gt;\&lt;/span&gt;
 ca-certificates &lt;span class="se"&gt;\&lt;/span&gt;
 curl &lt;span class="se"&gt;\&lt;/span&gt;
 gnupg &lt;span class="se"&gt;\&lt;/span&gt;
 lsb-release &lt;span class="se"&gt;\&lt;/span&gt;
 jq &lt;span class="se"&gt;\&lt;/span&gt;
 software-properties-common &lt;span class="se"&gt;\&lt;/span&gt;
 unzip

&lt;span class="c"&gt;# Install Tools from Private Repos&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;terraform
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;vault
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;kubectl
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;helm
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;java-17-amazon-corretto-jdk
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;google-cloud-cli
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;azure-cli
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;docker-ce &lt;span class="se"&gt;\&lt;/span&gt;
                 docker-ce-cli &lt;span class="se"&gt;\&lt;/span&gt;
                 containerd.io &lt;span class="se"&gt;\&lt;/span&gt;
                 docker-buildx-plugin &lt;span class="se"&gt;\&lt;/span&gt;
                 docker-compose-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tools Installed as Binaries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;# install AWS CLI&lt;/span&gt;
  install_binary_aws_cli
  install_binary_okta_aws_cli

  &lt;span class="c"&gt;# install other binaries&lt;/span&gt;
  install_binary_kustomize
  install_binary_helmfile
&lt;span class="o"&gt;}&lt;/span&gt;

install_binary_kustomize&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;URL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"&lt;/span&gt;
  &lt;span class="nv"&gt;URL_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://raw.githubusercontent.com/&lt;/span&gt;&lt;span class="nv"&gt;$URL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL_SCRIPT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | bash
  &lt;span class="nb"&gt;sudo mv&lt;/span&gt; ~/kustomize /usr/local/bin
&lt;span class="o"&gt;}&lt;/span&gt;

install_binary_helmfile&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"amd64"&lt;/span&gt;
  &lt;span class="nv"&gt;VER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.2.3"&lt;/span&gt;
  &lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"helmfile_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_linux_&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
  &lt;span class="nv"&gt;URL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"helmfile/helmfile/releases/download/v&lt;/span&gt;&lt;span class="nv"&gt;$VER&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$PKG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/&lt;/span&gt;&lt;span class="nv"&gt;$URL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xz&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;sudo mv&lt;/span&gt; &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;/helmfile /usr/local/bin
  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

install_binary_okta_aws_cli&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"amd64"&lt;/span&gt;
  &lt;span class="nv"&gt;VER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2.5.1"&lt;/span&gt;
  &lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"okta-aws-cli_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_linux_&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
  &lt;span class="nv"&gt;URL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"okta/okta-aws-cli/releases/download/v&lt;/span&gt;&lt;span class="nv"&gt;$VER&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$PKG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/&lt;/span&gt;&lt;span class="nv"&gt;$URL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xz&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;sudo mv&lt;/span&gt; &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;/okta-aws-cli /usr/local/bin
  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

install_binary_aws_cli&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"awscli-exe-linux-x86_64.zip"&lt;/span&gt;
  wget &lt;span class="s2"&gt;"https://awscli.amazonaws.com/&lt;/span&gt;&lt;span class="nv"&gt;$PKG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt; &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;
  unzip &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;/&lt;span class="nv"&gt;$PKG&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;
  &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;/aws/install
  &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; TEMP_DIR
&lt;span class="o"&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Installations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# verify installations&lt;/span&gt;
terraform &lt;span class="nt"&gt;--version&lt;/span&gt;
vault &lt;span class="nt"&gt;--version&lt;/span&gt;
kubectl version &lt;span class="nt"&gt;--client&lt;/span&gt;
helm version
kustomize version
helmfile &lt;span class="nt"&gt;--version&lt;/span&gt;
java &lt;span class="nt"&gt;--version&lt;/span&gt;
aws &lt;span class="nt"&gt;--version&lt;/span&gt;
okta-aws-cli &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Plugins
&lt;/h2&gt;

&lt;p&gt;Both helm and Kubernetes can extend their functionality through a plugin. Here’s how you can get some popular plugins for these tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Helm Plugins
&lt;/h3&gt;

&lt;p&gt;Helm has a few plugins that you can install, as shown below. I highly recommend the helm-diff, as this allows you to see what resources you will modify before installing or upgrading the the application.&lt;/p&gt;

&lt;p&gt;Here are some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/databus23/helm-diff
helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/aslafy-z/helm-git
helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/hypnoglow/helm-s3.git
helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/jkroepke/helm-secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kubernetes Plugin Engine
&lt;/h3&gt;

&lt;p&gt;Kubernetes have a plugin system with Kubernetes Krew, which you can install using the script below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  install_krew

  &lt;span class="c"&gt;# Add this in your startup scripts &lt;/span&gt;
  &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW_ROOT&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.krew&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

install_krew&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;pushd&lt;/span&gt; &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;

  &lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'[:upper:]'&lt;/span&gt; &lt;span class="s1"&gt;'[:lower:]'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;
    &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/x86_64/amd64/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\(arm\)\(64\)\?.*/\1\2/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/aarch64$/arm64/'&lt;/span&gt;
  &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"krew-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
  &lt;span class="nv"&gt;URL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kubernetes-sigs/krew/releases/latest/download/&lt;/span&gt;&lt;span class="nv"&gt;$PKG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/&lt;/span&gt;&lt;span class="nv"&gt;$URL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  curl &lt;span class="nt"&gt;-fsSLO&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;tar &lt;/span&gt;zxvf &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
  ./&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;krew

  &lt;span class="nb"&gt;popd
  rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; TEMP_DIR
&lt;span class="o"&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kubernetes Plugins
&lt;/h3&gt;

&lt;p&gt;Once &lt;a href="https://krew.sigs.k8s.io/" rel="noopener noreferrer"&gt;krew&lt;/a&gt; is installed, you can install some popular plugins.&lt;/p&gt;

&lt;p&gt;Here are some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;neat
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;sort-manifests
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;ktop
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;tree
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;graph
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;cert-manager 
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;get-all
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;ice
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;deprecations
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;ns
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;access-matrix
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;pod-lens
kubectl krew &lt;span class="nb"&gt;install &lt;/span&gt;resource-capacity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Ubuntu is a powerful platform for development, but it can be surprisingly complex for new developers, especially when it comes to installing and maintaining modern DevOps tooling. Most online instructions are fragmented, outdated, or inconsistent in how they handle repositories, keys, and binary installs. This can lead inconsistencies across developer workstations as well as production environments.&lt;/p&gt;

&lt;p&gt;So my goal here is to reduce the complexity by providing consistent set of installation steps that follow best practices and rely on official sources wherever possible.&lt;/p&gt;

&lt;p&gt;This can help avoid environment drift, especially when install scripts like this pin the tool versions and are routinely tested. This will help avoid those situations where you’ll hear: “works on my laptop”…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fcxamuugxbwotaeulb73x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fcxamuugxbwotaeulb73x.png" alt="Ops Problem Now" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>terraform</category>
      <category>kubernetes</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>Essential DevOps Tools for macOS</title>
      <dc:creator>Joaquin Menchaca</dc:creator>
      <pubDate>Sat, 10 Jan 2026 00:43:09 +0000</pubDate>
      <link>https://dev.to/joachim8675309/essential-devops-tools-for-macos-53m2</link>
      <guid>https://dev.to/joachim8675309/essential-devops-tools-for-macos-53m2</guid>
      <description>&lt;p&gt;This guide walks through installing popular tools for cloud provisioning and container management on &lt;a href="https://grokipedia.com/page/MacOS" rel="noopener noreferrer"&gt;macOS&lt;/a&gt;. While many may not realize it, &lt;a href="https://grokipedia.com/page/MacOS" rel="noopener noreferrer"&gt;macOS&lt;/a&gt; traces its roots back to &lt;strong&gt;&lt;a href="https://grokipedia.com/page/NeXTSTEP" rel="noopener noreferrer"&gt;NeXTSTEP&lt;/a&gt;&lt;/strong&gt; and is built on the &lt;a href="https://grokipedia.com/page/Mach_(kernel)" rel="noopener noreferrer"&gt;Mach&lt;/a&gt;-derived &lt;a href="https://grokipedia.com/page/XNU" rel="noopener noreferrer"&gt;XNU&lt;/a&gt; kernel. The &lt;a href="https://grokipedia.com/page/Darwin_(operating_system)" rel="noopener noreferrer"&gt;Darwin&lt;/a&gt; userland provides a &lt;a href="https://grokipedia.com/page/Comparison_of_BSD_operating_systems" rel="noopener noreferrer"&gt;BSD&lt;/a&gt;-based &lt;a href="https://grokipedia.com/page/Unix" rel="noopener noreferrer"&gt;Unix&lt;/a&gt; environment with familiar &lt;a href="https://grokipedia.com/page/POSIX" rel="noopener noreferrer"&gt;POSIX&lt;/a&gt; tools, along with macOS-specific additions such as the launchd init and service management system. This &lt;a href="https://grokipedia.com/page/Unix" rel="noopener noreferrer"&gt;Unix&lt;/a&gt; heritage is what allows many &lt;a href="https://grokipedia.com/page/Linux" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;-focused cloud and container tools to run reliably on &lt;a href="https://grokipedia.com/page/MacOS" rel="noopener noreferrer"&gt;macOS&lt;/a&gt; with minimal differences.&lt;/p&gt;

&lt;p&gt;The challenge arises when scripts written for &lt;a href="https://grokipedia.com/page/Linux" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;-based cloud environments are run on &lt;a href="https://grokipedia.com/page/MacOS" rel="noopener noreferrer"&gt;macOS&lt;/a&gt;. Because &lt;a href="https://grokipedia.com/page/MacOS" rel="noopener noreferrer"&gt;macOS&lt;/a&gt; ships with &lt;a href="https://grokipedia.com/page/Comparison_of_BSD_operating_systems" rel="noopener noreferrer"&gt;BSD&lt;/a&gt;-flavored utilities, such as &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;sed&lt;/code&gt;, and &lt;code&gt;awk&lt;/code&gt;, scripts that work correctly on &lt;a href="https://grokipedia.com/page/Linux" rel="noopener noreferrer"&gt;Linux&lt;/a&gt; may behave differently or fail entirely. To address this, this guide not only covers installing cloud provisioning tools like &lt;a href="https://developer.hashicorp.com/terraform" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; and &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; tooling, but also walks through installing a common set of command-line tools so that scripts behave consistently across both &lt;a href="https://grokipedia.com/page/Linux" rel="noopener noreferrer"&gt;Linux&lt;/a&gt; and &lt;a href="https://grokipedia.com/page/MacOS" rel="noopener noreferrer"&gt;macOS&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tools
&lt;/h2&gt;

&lt;p&gt;This is an overview of the tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Provisioning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/terraform" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; [&lt;code&gt;terraform&lt;/code&gt;]: tool for provisioning cloud infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; [&lt;code&gt;aws&lt;/code&gt;]: tool to interact with Amazon Web Services&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/okta/okta-aws-cli" rel="noopener noreferrer"&gt;okta-aws-cli&lt;/a&gt; [&lt;code&gt;okta-aws-cli&lt;/code&gt;]: allows you to get temporary IAM credentials using Okta as the Identity provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Kubernetes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/reference/kubectl/" rel="noopener noreferrer"&gt;Kubernetes CLI &lt;/a&gt;[&lt;code&gt;kubectl&lt;/code&gt;]: command line tool for interacting with Kubernetes control plan&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; [&lt;code&gt;helm&lt;/code&gt;]: Tool for configuring, installing, and distributing Kubernetes applications.&lt;/li&gt;
&lt;li&gt;[Kustomize] [&lt;code&gt;kustomize&lt;/code&gt;]: tool to configure Kubernetes application through patching.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kustomize.io/" rel="noopener noreferrer"&gt;Helmfile&lt;/a&gt; [&lt;code&gt;helmfile&lt;/code&gt;]: is a declarative spec for deploying helm charts that allows you to template helm chart values as well integrate patching support&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://krew.sigs.k8s.io/" rel="noopener noreferrer"&gt;Krew&lt;/a&gt; [&lt;code&gt;kubectl krew&lt;/code&gt;]: is a plugin system for Kubernetes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Java
&lt;/h3&gt;

&lt;p&gt;Beyond compiling languages and running java programs, there are tools to manage certificate, keytool, and a useful tool for managing tar archives: jar.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/corretto/" rel="noopener noreferrer"&gt;Correto OpenJDK&lt;/a&gt; [&lt;code&gt;java&lt;/code&gt;, &lt;code&gt;javac&lt;/code&gt;, &lt;code&gt;jar&lt;/code&gt;, &lt;code&gt;keytool&lt;/code&gt;]: Corretto is an OpenJDK distribution that is supported on many platforms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Others
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.hashicorp.com/vault" rel="noopener noreferrer"&gt;Vault&lt;/a&gt; [&lt;code&gt;vault&lt;/code&gt;]: Allow securing, storing, and controlling access to secrets artifacts: tokens, passwords, certificates, and encryption keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Package System
&lt;/h2&gt;

&lt;p&gt;You can install &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt; with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install XCode command line tools&lt;/span&gt;
xcode-select &lt;span class="nt"&gt;--install&lt;/span&gt;

&lt;span class="c"&gt;# Install Homebrew&lt;/span&gt;
&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh"&lt;/span&gt;
/bin/bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; &lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Common Core Commands
&lt;/h2&gt;

&lt;p&gt;These commands represent a common set of tools I use across Linux and Windows MSYS2 environments. They include GNU utilities such as &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;find&lt;/code&gt;, &lt;code&gt;gawk&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, and &lt;code&gt;sed&lt;/code&gt;, along with commonly used tools like &lt;code&gt;bc&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;git&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt;, and &lt;code&gt;zsh&lt;/code&gt;. While macOS includes some of these commands by default, they are often BSD variants with different behavior or significantly older versions that lack features commonly relied upon in scripts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install common core commands (GNU + bc, curl, jq, zsh) &lt;/span&gt;
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  autoconf &lt;span class="se"&gt;\&lt;/span&gt;
  bash &lt;span class="se"&gt;\&lt;/span&gt;
  bc &lt;span class="se"&gt;\&lt;/span&gt;
  binutils &lt;span class="se"&gt;\&lt;/span&gt;
  coreutils &lt;span class="se"&gt;\&lt;/span&gt;
  curl &lt;span class="se"&gt;\&lt;/span&gt;
  diffutils &lt;span class="se"&gt;\&lt;/span&gt;
  ed &lt;span class="se"&gt;\&lt;/span&gt;
  findutils &lt;span class="se"&gt;\&lt;/span&gt;
  flex &lt;span class="se"&gt;\&lt;/span&gt;
  gawk &lt;span class="se"&gt;\&lt;/span&gt;
  git &lt;span class="se"&gt;\&lt;/span&gt;
  gnu-indent &lt;span class="se"&gt;\&lt;/span&gt;
  gnu-sed &lt;span class="se"&gt;\&lt;/span&gt;
  gnu-tar &lt;span class="se"&gt;\&lt;/span&gt;
  gnu-which &lt;span class="se"&gt;\&lt;/span&gt;
  gpatch &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;gzip&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  jq &lt;span class="se"&gt;\&lt;/span&gt;
  less &lt;span class="se"&gt;\&lt;/span&gt;
  m4 &lt;span class="se"&gt;\&lt;/span&gt;
  make &lt;span class="se"&gt;\&lt;/span&gt;
  nano &lt;span class="se"&gt;\&lt;/span&gt;
  screen &lt;span class="se"&gt;\&lt;/span&gt;
  watch &lt;span class="se"&gt;\&lt;/span&gt;
  wdiff &lt;span class="se"&gt;\&lt;/span&gt;
  wget &lt;span class="se"&gt;\&lt;/span&gt;
  zip &lt;span class="se"&gt;\&lt;/span&gt;
  zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Available Shells
&lt;/h3&gt;

&lt;p&gt;You can run this to make these updated shells available to your environment by appending them to &lt;code&gt;/etc/shells&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;brew &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/bin/bash"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/shells
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;brew &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/bin/zsh"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/shells
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Default Shell
&lt;/h3&gt;

&lt;p&gt;While I prefer &lt;a href="https://www.zsh.org/" rel="noopener noreferrer"&gt;Zsh&lt;/a&gt; as my default interactive shell due to its rich prompt and plugin ecosystem provided by &lt;a href="https://ohmyz.sh/" rel="noopener noreferrer"&gt;Oh My Zsh!&lt;/a&gt;, all of my scripts are written and tested using &lt;a href="https://www.gnu.org/software/bash/" rel="noopener noreferrer"&gt;GNU Bash&lt;/a&gt; for portability and consistency.&lt;/p&gt;

&lt;p&gt;You can change your default shell using one of the commands below to the shell of your choice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;chsh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;brew &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/bin/bash
chsh &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;brew &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/bin/zsh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When running shell scripts, use &lt;code&gt;env&lt;/code&gt; command for your shebang to select the shell from your path, rather than override with a dinosaur version of the shell provided by the system.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bash shebang line&lt;/strong&gt;: &lt;code&gt;#!/usr/bin/env bash&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zsh shebang line&lt;/strong&gt;: &lt;code&gt;#!/usr/bin/env zsh&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Paths
&lt;/h3&gt;

&lt;p&gt;These new GNU commands and other Keg-only commands will not be available for scripts, so they need to be added to the &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You will want to add this below to your startup scripts, like &lt;code&gt;.bash_profile&lt;/code&gt; or &lt;code&gt;.zshrc&lt;/code&gt; for macOS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;update_homebrew_path&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;BREW_PREFIX
  &lt;span class="nb"&gt;local &lt;/span&gt;GNU_PATHS
  &lt;span class="nb"&gt;local &lt;/span&gt;KEG_PATHS
  &lt;span class="nb"&gt;local &lt;/span&gt;COMBINED_PATHS
  &lt;span class="nb"&gt;local &lt;/span&gt;DEDUPE_SCRIPT

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; brew &amp;amp;&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then return fi

  &lt;/span&gt;&lt;span class="nv"&gt;BREW_PREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;brew &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;GNU_PATHS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s:"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BREW_PREFIX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/opt/"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="s2"&gt;"/libexec/gnubin"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;KEG_PATHS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;
    brew info &lt;span class="nt"&gt;--installed&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v1 &lt;span class="se"&gt;\&lt;/span&gt;
      | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'map(select(.keg_only == true)) | .[].name'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
      | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; PKG&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
          if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BREW_PREFIX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/opt/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s2"&gt;"%s:"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BREW_PREFIX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/opt/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin"&lt;/span&gt;
          &lt;span class="k"&gt;fi
        done&lt;/span&gt;
  &lt;span class="si"&gt;)&lt;/span&gt;

  &lt;span class="nv"&gt;COMBINED_PATHS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GNU_PATHS&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;KEG_PATHS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;DEDUPE_SCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'print join ":", grep { ! $seen{$_}++ } split /:/, shift'&lt;/span&gt;

  perl &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DEDUPE_SCRIPT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;COMBINED_PATHS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/^://; s/:$//'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;NEW_PATHS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;update_homebrew_path&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NEW_PATHS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Installation
&lt;/h2&gt;

&lt;p&gt;Now that we have the basic consistent core commands available, we can install &lt;strong&gt;cloud provisioning&lt;/strong&gt; (&lt;code&gt;terraform&lt;/code&gt;), &lt;strong&gt;Kubernetes&lt;/strong&gt; tools (&lt;code&gt;kubectl&lt;/code&gt;, &lt;code&gt;helm&lt;/code&gt;, &lt;code&gt;helmfile&lt;/code&gt;, &lt;code&gt;kustomize&lt;/code&gt;), &lt;strong&gt;Corretto&lt;/strong&gt; (&lt;code&gt;java&lt;/code&gt;, &lt;code&gt;jar&lt;/code&gt;, &lt;code&gt;keytool&lt;/code&gt;), and other tools (&lt;code&gt;vault&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install AWS CLI&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;awscli
brew &lt;span class="nb"&gt;install &lt;/span&gt;okta-aws-cli

&lt;span class="c"&gt;# install packages&lt;/span&gt;
brew tap hashicorp/tap
brew &lt;span class="nb"&gt;install &lt;/span&gt;hashicorp/tap/terraform
brew &lt;span class="nb"&gt;install &lt;/span&gt;hashicorp/tap/vault
brew &lt;span class="nb"&gt;install &lt;/span&gt;kubernetes-cli  &lt;span class="c"&gt;# kubectl&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;helm &lt;span class="c"&gt;# helm&lt;/span&gt;

&lt;span class="c"&gt;# Java&lt;/span&gt;
brew tap homebrew/cask-versions
brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; corretto17

&lt;span class="c"&gt;# Helmfile and Kustomize&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;kustomize
brew &lt;span class="nb"&gt;install &lt;/span&gt;helmfile

&lt;span class="c"&gt;# Other&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verification
&lt;/h3&gt;

&lt;p&gt;You can verify the tool installations with the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# verify installations&lt;/span&gt;
terraform &lt;span class="nt"&gt;--version&lt;/span&gt;
vault &lt;span class="nt"&gt;--version&lt;/span&gt;
kubectl version &lt;span class="nt"&gt;--client&lt;/span&gt;
helm version
kustomize version
helmfile &lt;span class="nt"&gt;--version&lt;/span&gt;
java &lt;span class="nt"&gt;--version&lt;/span&gt;
aws &lt;span class="nt"&gt;--version&lt;/span&gt;
okta-aws-cli &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Plugins
&lt;/h2&gt;

&lt;p&gt;Both helm and Kubernetes can extend their functionality through a plugin. Here’s how you can get some popular plugins for these tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Helm Plugins
&lt;/h3&gt;

&lt;p&gt;Helm has a few plugins that you can install, as shown below. I highly recommend the helm-diff, as this allows you to see what resources you will modify before installing or upgrading the the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/databus23/helm-diff
helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/aslafy-z/helm-git
helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/hypnoglow/helm-s3.git
helm plugin &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/jkroepke/helm-secrets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kubernetes Plugin Engine
&lt;/h3&gt;

&lt;p&gt;Kubernetes has a plugin system with Kubernetes Krew.  You can use this script below to install Krew.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  install_krew
  &lt;span class="c"&gt;# Add this in your startup scripts &lt;/span&gt;
  &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW_ROOT&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.krew&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/bin:&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

install_krew&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;TEMP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;pushd&lt;/span&gt; &lt;span class="nv"&gt;$TEMP_DIR&lt;/span&gt;
  &lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="s1"&gt;'[:upper:]'&lt;/span&gt; &lt;span class="s1"&gt;'[:lower:]'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;
    &lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/x86_64/amd64/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/\(arm\)\(64\)\?.*/\1\2/'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/aarch64$/arm64/'&lt;/span&gt;
  &lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"krew-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
  &lt;span class="nv"&gt;URL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"kubernetes-sigs/krew/releases/latest/download/&lt;/span&gt;&lt;span class="nv"&gt;$PKG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/&lt;/span&gt;&lt;span class="nv"&gt;$URL_PATH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  curl &lt;span class="nt"&gt;-fsSLO&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;tar &lt;/span&gt;zxvf &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
  ./&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;KREW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;krew
  &lt;span class="nb"&gt;popd
  rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; TEMP_DIR
&lt;span class="o"&gt;}&lt;/span&gt;

main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Extra: The Package Manifest
&lt;/h2&gt;

&lt;p&gt;Homebrew supports using a package manifest that list all the packages in a single file called &lt;code&gt;Brewfile&lt;/code&gt;.  Create a file named &lt;code&gt;Brewfile&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Common Core Commands&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'autoconf'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'bash'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'bc'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'binutils'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'coreutils'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'curl'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'diffutils'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'ed'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'findutils'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'flex'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'gawk'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'git'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'gnu-indent'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'gnu-sed'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'gnu-tar'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'gnu-which'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'gpatch'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'grep'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'gzip'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'jq'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'less'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'m4'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'make'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'nano'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'screen'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'watch'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'wdiff'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'wget'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'zip'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'zsh'&lt;/span&gt;

&lt;span class="c1"&gt;# AWS Tools&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'awscli'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'okta-aws-cli'&lt;/span&gt;
&lt;span class="c1"&gt;# Hashicorp&lt;/span&gt;
&lt;span class="n"&gt;tap&lt;/span&gt; &lt;span class="s1"&gt;'hashicorp/tap'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'hashicorp/tap/terraform'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'hashicorp/tap/vault'&lt;/span&gt;
&lt;span class="c1"&gt;# Kubernetes&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'kubernetes-cli'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'helm'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'kustomize'&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'helmfile'&lt;/span&gt;
&lt;span class="c1"&gt;# Java&lt;/span&gt;
&lt;span class="n"&gt;tap&lt;/span&gt; &lt;span class="s1"&gt;'homebrew/cask-versions'&lt;/span&gt;
&lt;span class="n"&gt;cask&lt;/span&gt; &lt;span class="s1"&gt;'corretto17'&lt;/span&gt;
&lt;span class="c1"&gt;# Other&lt;/span&gt;
&lt;span class="n"&gt;brew&lt;/span&gt; &lt;span class="s1"&gt;'jq'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When ready, you can install packages listed in the &lt;code&gt;Brewfile&lt;/code&gt; with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew bundle &lt;span class="nt"&gt;--verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to set up the &lt;code&gt;PATH&lt;/code&gt; correctly to include the paths to GNU and Keg-only commands. Also, update the available shells in &lt;code&gt;/etc/shells&lt;/code&gt; to that your new version of &lt;code&gt;zsh&lt;/code&gt; and &lt;code&gt;bash&lt;/code&gt; are available. &lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>terraform</category>
      <category>macos</category>
    </item>
    <item>
      <title>Loki: Getting Started</title>
      <dc:creator>Joaquin Menchaca</dc:creator>
      <pubDate>Sun, 06 Aug 2023 23:22:44 +0000</pubDate>
      <link>https://dev.to/joachim8675309/loki-getting-started-n8o</link>
      <guid>https://dev.to/joachim8675309/loki-getting-started-n8o</guid>
      <description>&lt;p&gt;The realm of open source log aggregators has seen significant growth over the years, with key players like &lt;a href="https://www.elastic.co/elastic-stack" rel="noopener noreferrer"&gt;ElasticSearch&lt;/a&gt; (2010) and &lt;a href="https://graylog.org/" rel="noopener noreferrer"&gt;Graylog&lt;/a&gt; (2016) dominating the field. More recently, &lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;Grafana Loki&lt;/a&gt; (2019) has emerged as a compelling addition to this ecosystem. &lt;/p&gt;

&lt;p&gt;This article aims to facilitate a rapid onboarding process for log shipping using &lt;a href="https://grafana.com/docs/loki/latest/clients/promtail/" rel="noopener noreferrer"&gt;Promtail&lt;/a&gt;, log aggregation with &lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;Loki&lt;/a&gt;, and data visualization through &lt;a href="https://grafana.com/oss/grafana/" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt;. Collectively, this powerful trio of tools is commonly referred to as the PLG (Promtail-Loki-Grafana) stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Server System
&lt;/h2&gt;

&lt;p&gt;These instructions will work on Debian or Ubuntu system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Vagrant (Virtualbox)
&lt;/h3&gt;

&lt;p&gt;If you have Intel system, you can use &lt;a href="https://www.vagrantup.com/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; with &lt;a href="https://www.virtualbox.org/" rel="noopener noreferrer"&gt;Virtualbox&lt;/a&gt; to quickly bring up virtual servers on your workstation.  Follow the instructions from respect sites to install these tools.&lt;/p&gt;

&lt;p&gt;When ready, create a file called &lt;code&gt;Vagrantfile&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;

&lt;span class="no"&gt;Vagrant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"generic/ubuntu2204"&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;network&lt;/span&gt; &lt;span class="s2"&gt;"forwarded_port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;guest: &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;host_ip: &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;network&lt;/span&gt; &lt;span class="s2"&gt;"forwarded_port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;guest: &lt;/span&gt;&lt;span class="mi"&gt;3100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="mi"&gt;3100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;host_ip: &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: For this setup, the configuration will utilize &lt;code&gt;3000&lt;/code&gt; for &lt;a href="https://grafana.com/oss/grafana/" rel="noopener noreferrer"&gt;Grafana&lt;/a&gt; and &lt;code&gt;3100&lt;/code&gt; for &lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;Loki&lt;/a&gt; on the localhost. If any services are currently running on these ports, you'll have to either halt those services or modify the host: key in the provided above configuration to use an alternative port.&lt;/p&gt;

&lt;p&gt;When ready, you can bring up the system and log into the system with the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

vagrant up
vagrant ssh


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Installing Loki
&lt;/h3&gt;

&lt;p&gt;On your desired system, such as the &lt;a href="https://www.vagrantup.com/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; managed virtual machine above, you can run the following to install PLG:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; apt-transport-https
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; software-properties-common wget
&lt;span class="nb"&gt;sudo &lt;/span&gt;wget &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; /usr/share/keyrings/grafana.key &lt;span class="se"&gt;\&lt;/span&gt;
  https://apt.grafana.com/gpg.key

&lt;span class="c"&gt;# add a repository for stable releases&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/apt/sources.list.d/grafana.list

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; promtail loki grafana


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Verify Services are running
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;service loki status
&lt;span class="nb"&gt;sudo &lt;/span&gt;service grafana-server status


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If any of these services are stopped, you can run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;service loki start
&lt;span class="nb"&gt;sudo &lt;/span&gt;service grafana-server start


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  The Client Workstation
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Visualization
&lt;/h3&gt;

&lt;p&gt;You can access the login page by opening a web browser on your system and navigating to &lt;a href="http://127.0.0.1:3000" rel="noopener noreferrer"&gt;http://127.0.0.1:3000&lt;/a&gt;. Simply use the default credentials, admin for both the username and password. Upon login, you will be prompted to set a new password for the admin account.&lt;/p&gt;

&lt;p&gt;After logging in, you can click on Explore, Loki, and then select on of the logs by clicking on Label.&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%2Fujyociv0oapsro55x8uy.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%2Fujyociv0oapsro55x8uy.png" alt="Screen Shot of Grafana UI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Ship More Logs with Promtail
&lt;/h3&gt;

&lt;p&gt;When setting up a new system, there may not be many interesting logs initially. However, your host workstation system is likely to have accumulated a wealth of interesting logs over time.&lt;/p&gt;

&lt;p&gt;If you are running the server as a virtual machine using the previously mentioned &lt;code&gt;Vagrantfile&lt;/code&gt; configuration, you can easily ship logs from the laptop to &lt;code&gt;localhost:3100&lt;/code&gt;, where &lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;Loki&lt;/a&gt; is up and running. This allows you to leverage the abundant logs from your host workstation for analysis and visualization.&lt;/p&gt;

&lt;p&gt;You can install &lt;a href="https://grafana.com/docs/loki/latest/clients/promtail/" rel="noopener noreferrer"&gt;Promtail&lt;/a&gt; locally as well. If the host system is running Debian or Ubuntu, you can run this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;# add a repository for stable releases&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;wget &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; /usr/share/keyrings/grafana.key &lt;span class="se"&gt;\&lt;/span&gt;
  https://apt.grafana.com/gpg.key
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/apt/sources.list.d/grafana.list

&lt;span class="c"&gt;# install promtail&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; promtail


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By default, the configuration file &lt;code&gt;/etc/promtail/config.yml&lt;/code&gt; will set up Promtail to ship logs to the URL: &lt;code&gt;http://localhost:3100/loki/api/v1/push&lt;/code&gt;. This configuration will function correctly if you are using &lt;a href="https://www.vagrantup.com/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; with &lt;a href="https://www.virtualbox.org/" rel="noopener noreferrer"&gt;Virtualbox&lt;/a&gt; to run &lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;Loki&lt;/a&gt;. However, if you are not running the &lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;Loki&lt;/a&gt; server locally, you will need to modify the address (currently set to &lt;code&gt;localhost&lt;/code&gt;) in the configuration accordingly.&lt;/p&gt;

&lt;p&gt;As an option you can modify the configuration with the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;http_listen_port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9080&lt;/span&gt;
  &lt;span class="na"&gt;grpc_listen_port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="na"&gt;positions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp/positions.yaml&lt;/span&gt;

&lt;span class="na"&gt;clients&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3100/loki/api/v1/push&lt;/span&gt;

&lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system&lt;/span&gt;
  &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;job&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;varlogs&lt;/span&gt;
      &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my_workstation&lt;/span&gt;
      &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;promtail&lt;/span&gt;
      &lt;span class="na"&gt;__path__&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/log/*log&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And later restart the service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart promtail


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>logaggregator</category>
      <category>observability</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Ultimate EKS Baseline Cluster: Part 2 - Storage</title>
      <dc:creator>Joaquin Menchaca</dc:creator>
      <pubDate>Mon, 24 Jul 2023 00:56:03 +0000</pubDate>
      <link>https://dev.to/joachim8675309/ultimate-eks-baseline-cluster-part-2-storage-3kpi</link>
      <guid>https://dev.to/joachim8675309/ultimate-eks-baseline-cluster-part-2-storage-3kpi</guid>
      <description>&lt;p&gt;This may come as a surprise to some, but the AWS managed Kubernetes service, &lt;a href="https://aws.amazon.com/eks/"&gt;EKS&lt;/a&gt; (&lt;a href="https://aws.amazon.com/eks/"&gt;Elastic Kubernetes Service&lt;/a&gt;), no longer comes with support for storage through Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/"&gt;persistent volumes&lt;/a&gt;, which is required for many applications, such as databases.&lt;/p&gt;

&lt;p&gt;You will need to add a (&lt;a href="https://kubernetes.io/blog/2019/01/15/container-storage-interface-ga/"&gt;CSI&lt;/a&gt;) driver to enable &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/"&gt;persistent volumes&lt;/a&gt; support.&lt;/p&gt;

&lt;p&gt;This guide, Part 2 of &lt;em&gt;Ultimate EKS Baseline Cluster&lt;/em&gt; series,  covers doing just that by installing &lt;a href="https://kubernetes.io/blog/2019/01/15/container-storage-interface-ga/"&gt;CSI&lt;/a&gt;) called &lt;a href="https://github.com/kubernetes-sigs/aws-ebs-csi-driver"&gt;AWS EBS CSI Driver&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  0. Prerequisites
&lt;/h2&gt;

&lt;p&gt;These are are some prerequisites and initial steps needed to get started before provisioning a Kubernetes cluster and installing add-ons.&lt;/p&gt;

&lt;h3&gt;
  
  
  0.1 Knowledge: Systems
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q1OrSwOU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqzshuffp4kni7i9t487.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q1OrSwOU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqzshuffp4kni7i9t487.png" alt="image of system concept icons" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basic concepts of systems, such as Linux and the shell (redirection, pipes, process substitution, command substitution, environment variables), as well as virtualization and containers are useful. The concept of a service (daemon) is important.&lt;/p&gt;

&lt;h3&gt;
  
  
  0.2 Knowledge: Kubernetes
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oOvemFw5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5i7xyp8oty9jp44r0dv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oOvemFw5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5i7xyp8oty9jp44r0dv.png" alt="image of Kubernetes concept icons" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Kubernetes, familiarity with service types: ClusterIP, NodePort, LoadBalancer, ExternalName and the ingress resource are important.&lt;/p&gt;

&lt;p&gt;Exposure to other types of Kubernetes resource objects used in this guide are helpful: &lt;code&gt;persistentvolumeclaims&lt;/code&gt; (&lt;code&gt;pvc&lt;/code&gt;), &lt;code&gt;storageclass&lt;/code&gt; (&lt;code&gt;sc&lt;/code&gt;), &lt;code&gt;pods&lt;/code&gt;, &lt;code&gt;deployments&lt;/code&gt;, &lt;code&gt;statefulsets&lt;/code&gt; (&lt;code&gt;sts&lt;/code&gt;), &lt;code&gt;configmaps&lt;/code&gt;, &lt;code&gt;serviceaccount&lt;/code&gt; (&lt;code&gt;sa&lt;/code&gt;) and &lt;code&gt;networkpolicies&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  0.3 Tools
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ZkkVDOV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7u87et62nyhbwrksb29d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ZkkVDOV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7u87et62nyhbwrksb29d.png" alt="image of tool icons" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are the tools used in this article series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/cli/"&gt;AWS CLI&lt;/a&gt; [&lt;code&gt;aws&lt;/code&gt;] is a tool that interacts with AWS.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/reference/kubectl/"&gt;kubectl client&lt;/a&gt; [&lt;code&gt;kubectl&lt;/code&gt;] a the tool that can interact with the Kubernetes cluster. This can be installed using adsf tool.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://eksctl.io/"&gt;eksctl&lt;/a&gt; [eksctl] is the tool that can provision EKS cluster as well as supporting VPC network infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html"&gt;POSIX Shell&lt;/a&gt; [&lt;code&gt;sh&lt;/code&gt;] such as &lt;a href="https://www.gnu.org/software/bash/"&gt;bash&lt;/a&gt;[&lt;code&gt;bash&lt;/code&gt;] or &lt;a href="https://www.zsh.org/"&gt;zsh&lt;/a&gt; [&lt;code&gt;zsh&lt;/code&gt;] are used to run the commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools are highly recommended:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://asdf-vm.com/"&gt;adsf&lt;/a&gt; [&lt;code&gt;adsf&lt;/code&gt;] is a tool that installs versions of popular tools like kubectl.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jqlang.github.io/jq/"&gt;jq&lt;/a&gt; [&lt;code&gt;jq&lt;/code&gt;] is a tool to query and print JSON data&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gnu.org/software/grep/"&gt;GNU Grep&lt;/a&gt; [&lt;code&gt;grep&lt;/code&gt;] supports extracting string patterns using extended &lt;a href="https://en.wikipedia.org/wiki/Regular_expression"&gt;Regex&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions"&gt;PCRE&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  0.3 Setup Environment Variables
&lt;/h3&gt;

&lt;p&gt;These environment variables will be used throughout this guide. If opening up a new browser tab, make sure to set the environment variables accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# variables used to create EKS&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-aws-profile"&lt;/span&gt; &lt;span class="c"&gt;# CHANGEME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKS_CLUSTER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-unique-cluster-name"&lt;/span&gt; &lt;span class="c"&gt;# CHANGEME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKS_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKS_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.26"&lt;/span&gt;

&lt;span class="c"&gt;# KUBECONFIG variable&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/&lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt;.&lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt;.yaml

&lt;span class="c"&gt;# account id&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Account"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# ebs-csi-driver&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ROLE_NAME_ECSI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EKS_CLUSTER_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_EBS_CSI_DriverRole"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT_ROLE_ARN_ECSI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::&lt;/span&gt;&lt;span class="nv"&gt;$ACCOUNT_ID&lt;/span&gt;&lt;span class="s2"&gt;:role/&lt;/span&gt;&lt;span class="nv"&gt;$ROLE_NAME_ECSI&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;POLICY_NAME_ECSI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"AmazonEBSCSIDriverPolicy"&lt;/span&gt; &lt;span class="c"&gt;# preinstalled by AWS&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;POLICY_ARN_ECSI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::aws:policy/service-role/&lt;/span&gt;&lt;span class="nv"&gt;$POLICY_NAME_ECSI&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  0.4 AWS Setup
&lt;/h3&gt;

&lt;p&gt;There's an assumption that AWS CLI have been setup and configured with a profile. This is required before creating or interacting with an EKS cluster.&lt;/p&gt;

&lt;p&gt;You can test access to a configured profile with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-profile-goes-here&amp;gt;"&lt;/span&gt;
aws sts get-caller-identity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like the following with values appropriate to your environment, e.g. example output to IAM user named &lt;code&gt;kwisatzhaderach&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"UserId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AIDAXXXXXXXXXXXXXXXXX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XXXXXXXXXXXX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Arn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::XXXXXXXXXXXX:user/kwisatzhaderach"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  0.5 EKS Cluster
&lt;/h3&gt;

&lt;p&gt;This article requires that an EKS cluster has been previously provisioned using &lt;code&gt;eksctl&lt;/code&gt; tool.&lt;/p&gt;

&lt;p&gt;I wrote a previous article that covered this how to provision EKS with two commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/joachim8675309/ultimate-eks-baseline-cluster-part-1-provision-eks-17f"&gt;Ultimate EKS Baseline Cluster: Part 1 - Provision EKS &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  0.5.1 Existing EKS Cluster
&lt;/h4&gt;

&lt;p&gt;If you have an existing EKS cluster, but need to configure &lt;code&gt;KUBECONFIG&lt;/code&gt; for access, you can run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube &lt;span class="c"&gt;# conditionally create ~/.kube&lt;/span&gt;
&lt;span class="c"&gt;# use consistent $KUBECONFIG&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/&lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt;.&lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt;.yaml

&lt;span class="c"&gt;# update config pointed to by $KUBECONFIG &lt;/span&gt;
aws eks update-kubeconfig &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$CLUSTER&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--profile&lt;/span&gt; &lt;span class="nv"&gt;$PROFILE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  0.5.2 Create a new EKS Cluster
&lt;/h4&gt;

&lt;p&gt;If you have not setup an EKS cluster, you can set it up with the following commands (~20 minutes process):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube &lt;span class="c"&gt;# conditionally create ~/.kube&lt;/span&gt;
&lt;span class="c"&gt;# use consistent $KUBECONFIG&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/&lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt;.&lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt;.yaml

&lt;span class="c"&gt;# provision EKS + add config to $KUBECONFIG &lt;/span&gt;
eksctl create cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="nv"&gt;$EKS_VERSION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--nodes&lt;/span&gt; 3

&lt;span class="c"&gt;# setup OIDC provider for least privilege&lt;/span&gt;
eksctl utils associate-iam-oidc-provider &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Details of this were covered in the &lt;a href="https://dev.to/joachim8675309/ultimate-eks-baseline-cluster-part-1-provision-eks-17f"&gt;previous article&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  0.6 Kubernetes Client Setup
&lt;/h3&gt;

&lt;p&gt;If you use &lt;code&gt;asdf&lt;/code&gt; to install &lt;code&gt;kubectl&lt;/code&gt;, you can get the latest version with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install kubectl plugin for asdf&lt;/span&gt;
asdf plugin-add kubectl &lt;span class="se"&gt;\&lt;/span&gt;
  https://github.com/asdf-community/asdf-kubectl.git
asdf &lt;span class="nb"&gt;install &lt;/span&gt;kubectl latest

&lt;span class="c"&gt;# fetch latest kubectl &lt;/span&gt;
asdf &lt;span class="nb"&gt;install &lt;/span&gt;kubectl latest
asdf global kubectl latest

&lt;span class="c"&gt;# test results of latest kubectl &lt;/span&gt;
kubectl version &lt;span class="nt"&gt;--short&lt;/span&gt; &lt;span class="nt"&gt;--client&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Client Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1.27.4&lt;/span&gt;
&lt;span class="na"&gt;Kustomize Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v5.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1. AWS EBS CSI driver
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bBkzklPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bug7a5d2vpxzirfr6hs7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bBkzklPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bug7a5d2vpxzirfr6hs7.png" alt="Title bar with icons for EBS and CSI" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The current versions of &lt;a href="https://aws.amazon.com/eks/"&gt;EKS&lt;/a&gt; starting with 1.23 no longer come with a persistent volume support, so you have to install it on your own. The best method or at least the easiest way to install this, is using &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html"&gt;EKS add-ons&lt;/a&gt; facility. This will install the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html"&gt;EBS CSI driver&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Installation of this component will require the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html"&gt;IAM Role&lt;/a&gt; (e.g. &lt;code&gt;EBS_CSI_DriverRole&lt;/code&gt;) and associate it to &lt;a href="https://kubernetes.io/docs/concepts/security/service-accounts/"&gt;Kubernetes service account&lt;/a&gt; (i.e. &lt;code&gt;ebs-csi-controller-sa&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Deploy AWS EBS CSI driver using EKS add-ons facility, which also sets up the &lt;a href="https://kubernetes.io/docs/concepts/security/service-accounts/"&gt;Kubernetes service account&lt;/a&gt; (i.e. &lt;code&gt;ebs-csi-controller-sa&lt;/code&gt;) with an association back to the above &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html"&gt;IAM Role&lt;/a&gt; (e.g. &lt;code&gt;EBS_CSI_DriverRole&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Create storage class that uses new the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html"&gt;EBS CSI driver&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1.1 Setup IAM Role and K8S SA association
&lt;/h3&gt;

&lt;p&gt;The following process will create an &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html"&gt;IAM Role&lt;/a&gt; with permissions to access AWS EBS API. The service account &lt;code&gt;ebs-csi-controller-sa&lt;/code&gt; will be created later when installing the driver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# AWS IAM role bound to a Kubernetes service account&lt;/span&gt;
eksctl create iamserviceaccount &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"ebs-csi-controller-sa"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"kube-system"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attach-policy-arn&lt;/span&gt; &lt;span class="nv"&gt;$POLICY_ARN_ECSI&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-only&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME_ECSI&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html"&gt;IAM Role&lt;/a&gt;, which you can verify with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws iam get-role &lt;span class="nt"&gt;--role-name&lt;/span&gt; &lt;span class="nv"&gt;$ROLE_NAME_ECSI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"RoleName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mycluster_EBS_CSI_DriverRole"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"RoleId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AROAZYKZFDW7YZGW3Q5S7"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Arn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::XXXXXXXXXXXX:role/mycluster_EBS_CSI_DriverRole"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CreateDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-07-07T21:19:32+00:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AssumeRolePolicyDocument"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"Federated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::XXXXXXXXXXXX:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/6311CF96A267242FD6587B1C29D57F1D"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sts:AssumeRoleWithWebIdentity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"oidc.eks.us-west-2.amazonaws.com/id/6311CF96A267242FD6587B1C29D57F1D:aud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sts.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"oidc.eks.us-west-2.amazonaws.com/id/6311CF96A267242FD6587B1C29D57F1D:sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"system:serviceaccount:kube-system:ebs-csi-controller-sa"&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"MaxSessionDuration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alpha.eksctl.io/cluster-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mycluster"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eksctl.cluster.k8s.io/v1alpha1/cluster-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mycluster"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alpha.eksctl.io/iamserviceaccount-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kube-system/ebs-csi-controller-sa"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alpha.eksctl.io/eksctl-version"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.141.0-dev+5c8318ed5.2023-05-12T11:33:48Z"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"RoleLastUsed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.2 Install AWS EBS CSI Drvier
&lt;/h3&gt;

&lt;p&gt;This installation uses the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html"&gt;EKS Addons&lt;/a&gt; feature to install the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install Addon&lt;/span&gt;
eksctl create addon &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"aws-ebs-csi-driver"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-account-role-arn&lt;/span&gt; &lt;span class="nv"&gt;$ACCOUNT_ROLE_ARN_ECSI&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;span class="c"&gt;# Pause here until driver is active&lt;/span&gt;
&lt;span class="nv"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ACTIVE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  if &lt;/span&gt;eksctl get addon &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"aws-ebs-csi-driver"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
       &lt;span class="nt"&gt;--cluster&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $3}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="s2"&gt;"ACTIVE"&lt;/span&gt;
  &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nv"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;
  &lt;span class="k"&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to wait until status changes to &lt;code&gt;ACTIVE&lt;/code&gt; before proceeding.&lt;/p&gt;

&lt;p&gt;You can inspect the pods created by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"kube-system"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--selector&lt;/span&gt; &lt;span class="s2"&gt;"app.kubernetes.io/name=aws-ebs-csi-driver"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                                  READY   STATUS    RESTARTS   AGE
ebs-csi-controller-6d5b7bfd56-bwr5x   6/6     Running   0          2m1s
ebs-csi-controller-6d5b7bfd56-wtxf6   6/6     Running   0          2m2s
ebs-csi-node-hjmf5                    3/3     Running   0          2m2s
ebs-csi-node-tzpgs                    3/3     Running   0          2m2s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the service account annotations references the IAM Role for the EBS CSI driver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get serviceaccount &lt;span class="s2"&gt;"ebs-csi-controller-sa"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"kube-system"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;automountServiceAccountToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;eks.amazonaws.com/role-arn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;arn:aws:iam::XXXXXXXXXXXX:role/my-unique-cluster-name_EBS_CSI_DriverRole&lt;/span&gt;
  &lt;span class="na"&gt;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2023-07-24T21:12:02Z"&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/component&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;csi-driver&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/managed-by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;EKS&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-ebs-csi-driver&lt;/span&gt;
    &lt;span class="na"&gt;app.kubernetes.io/version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.21.0&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ebs-csi-controller-sa&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kube-system&lt;/span&gt;
  &lt;span class="na"&gt;resourceVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1922"&lt;/span&gt;
  &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1b8ecfdb-ce64-491c-8ced-e08b5519755c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1.2.1 Sidebar: eks-addons vs helm chart?
&lt;/h4&gt;

&lt;p&gt;The CSI driver can be installed using either &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html"&gt;EKS Addons&lt;/a&gt; facility from the previous step, or using the &lt;a href="https://artifacthub.io/packages/helm/aws-ebs-csi-driver/aws-ebs-csi-driver"&gt;aws-ebs-csi-driver&lt;/a&gt; Helm chart. I prefer the EKS addons because of simplicity, but also because it installs an extra snapshot container that doesn't come by default with the helm chart. &lt;/p&gt;

&lt;p&gt;I documented the full process using the helm chart in this article:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@joachim8675309/eks-ebs-storage-with-eksctl-3e526f534215"&gt;EKS + EBS Storage with eksctl&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.3 Create storage class that uses the EBS CSI driver
&lt;/h3&gt;

&lt;p&gt;In order to use the driver, we will need to create a storage class. You can do so by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# create ebs-sc storage class&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply --filename -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When completed you can verify the storage class was created with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get storageclass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME            PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
ebs-sc          ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   17s
gp2 (default)   kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  30m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.4 Set new storage class to the default (optional)
&lt;/h3&gt;

&lt;p&gt;This is an optional step. As there’s no functional default storage class, we can set the newly created storage class to be the default with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch storageclass gp2 &lt;span class="nt"&gt;--patch&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="s1"&gt;'{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'&lt;/span&gt;
kubectl patch storageclass ebs-sc &lt;span class="nt"&gt;--patch&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="s1"&gt;'{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, you can verify the change with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get storageclass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME               PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
ebs-sc (default)   ebs.csi.aws.com         Delete          WaitForFirstConsumer   true                   31s
gp2                kubernetes.io/aws-ebs   Delete          WaitForFirstConsumer   false                  30m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.5 Testing Persistent Volume
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OH3fjqZL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7uochrbvzgnd47q5zts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OH3fjqZL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7uochrbvzgnd47q5zts.png" alt="Image for title bar with icon for pvc" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this small test, we deploy a pod that continually writes to the external volume, and a volume claim to allocate storage using the storage class we created earlier.&lt;/p&gt;

&lt;p&gt;If this works, the storage will be provisioned in the cloud to create the volume, and then it will be attached to the node and mounted in the pod. If this fails, you will see that the pod will be stuck in &lt;code&gt;pending&lt;/code&gt; mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# create pod with persistent volume&lt;/span&gt;
kubectl create namespace &lt;span class="s2"&gt;"ebs-test"&lt;/span&gt;

&lt;span class="c"&gt;# deploy application with mounted volume&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;' | kubectl apply --namespace "ebs-test" --filename -
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: ubuntu
      command: ["/bin/sh"]
      args: ["-c", "while true; do echo &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt;&amp;gt; /data/out.txt; sleep 5; done"]
      volumeMounts:
      - name: persistent-storage
        mountPath: /data
  volumes:
    - name: persistent-storage
      persistentVolumeClaim:
        claimName: ebs-claim
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 4Gi
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can test the results of the volume creation with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all,pvc &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"ebs-test"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also look at the events that took place in this namespace with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl events &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"ebs-test"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will show something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LAST SEEN           TYPE      REASON                   OBJECT                            MESSAGE
56s                 Warning   FailedScheduling         Pod/app                           0/3 nodes are available: persistentvolumeclaim "ebs-claim" not found. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..
55s                 Normal    WaitForPodScheduled      PersistentVolumeClaim/ebs-claim   waiting for pod app to be scheduled
54s                 Normal    Provisioning             PersistentVolumeClaim/ebs-claim   External provisioner is provisioning volume for claim "ebs-test/ebs-claim"
54s (x2 over 54s)   Normal    ExternalProvisioning     PersistentVolumeClaim/ebs-claim   waiting for a volume to be created, either by external provisioner "ebs.csi.aws.com" or manually created by system administrator
50s                 Normal    Scheduled                Pod/app                           Successfully assigned ebs-test/app to ip-192-168-22-207.us-west-2.compute.internal
50s                 Normal    ProvisioningSucceeded    PersistentVolumeClaim/ebs-claim   Successfully provisioned volume pvc-39b9cf94-8b35-436c-b56d-e2fa587245ee
48s                 Normal    SuccessfulAttachVolume   Pod/app                           AttachVolume.Attach succeeded for volume "pvc-39b9cf94-8b35-436c-b56d-e2fa587245ee"
44s                 Normal    Pulling                  Pod/app                           Pulling image "ubuntu"
41s                 Normal    Pulled                   Pod/app                           Successfully pulled image "ubuntu" in 2.952872938s (2.952907339s including waiting)
41s                 Normal    Created                  Pod/app                           Created container app
41s                 Normal    Started                  Pod/app                           Started container app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.6 Delete test application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod app &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"ebs-test"&lt;/span&gt;
kubectl delete pvc ebs-claim &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"ebs-test"&lt;/span&gt;
kubectl delete ns &lt;span class="s2"&gt;"ebs-test"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2.0 Deleting EKS
&lt;/h2&gt;

&lt;p&gt;When deleting up the EKS cluster, you may want to run through these steps.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Deleting persistent volume claims
&lt;/h3&gt;

&lt;p&gt;When deleting EKS cluster, if you did not delete persistent volumes, you will have left over unused EBS volumes eating costs.&lt;/p&gt;

&lt;p&gt;You should delete all the persistent volume claims, which will delete associate persistent volumes.  You can list all of the &lt;code&gt;persistentvolumeclaim&lt;/code&gt; resources with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get persistentvolumeclaim &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not that some of these will not be deleted if there is an application running that has a lock to the storage.  So you will need to delete the associated application as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Reset Default to original Storage Class
&lt;/h3&gt;

&lt;p&gt;As a precaution, we don’t want to have any resources locked that may prevent deletion of the Kubernetes cluster. Run this command if we changed the defaults earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl patch storageclass ebs-sc &lt;span class="nt"&gt;--patch&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'&lt;/span&gt;
kubectl patch storageclass gp2 &lt;span class="nt"&gt;--patch&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3 IAM Roles
&lt;/h3&gt;

&lt;p&gt;These should be removed when removing Kubernetes with &lt;code&gt;eksctl&lt;/code&gt;, but it is a good practice to remove them just in case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl delete iamserviceaccount &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"ebs-csi-controller-sa"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"kube-system"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.4 Kubernetes cluster
&lt;/h3&gt;

&lt;p&gt;Finally, the Kubernetes cluster itself can be deleted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl delete cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This second article shows add support for storage, called persistent volumes on Kubernetes.  &lt;/p&gt;

&lt;p&gt;The automation using the &lt;code&gt;eksctl&lt;/code&gt; will do the following additional things besides provisioning EKS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup restricted access to AWS cloud resources using &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html"&gt;IRSA&lt;/a&gt;, which associates &lt;a href="https://kubernetes.io/docs/concepts/security/service-accounts/"&gt;KSA&lt;/a&gt; with &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html"&gt;IAM Role&lt;/a&gt; using an &lt;a href="https://openid.net/developers/how-connect-works/"&gt;OIDC&lt;/a&gt; provider.&lt;/li&gt;
&lt;li&gt;install applications using &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html"&gt;EKS addons&lt;/a&gt; facility, specifically the EBS CSI driver. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In future articles, I will cover how to add support for load balancers and network policies, as well as a demo application that demonstrates all of these features.&lt;/p&gt;

</description>
      <category>awscloud</category>
      <category>kubernetes</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Ultimate EKS Baseline Cluster: Part 1 - Provision EKS</title>
      <dc:creator>Joaquin Menchaca</dc:creator>
      <pubDate>Fri, 21 Jul 2023 19:14:52 +0000</pubDate>
      <link>https://dev.to/joachim8675309/ultimate-eks-baseline-cluster-part-1-provision-eks-17f</link>
      <guid>https://dev.to/joachim8675309/ultimate-eks-baseline-cluster-part-1-provision-eks-17f</guid>
      <description>&lt;p&gt;The AWS managed Kubernetes service, &lt;a href="https://aws.amazon.com/eks/" rel="noopener noreferrer"&gt;EKS&lt;/a&gt; (&lt;a href="https://aws.amazon.com/eks/" rel="noopener noreferrer"&gt;Elastic Kubernetes Service&lt;/a&gt;), has the highest level of complexity amongst cloud offerings. &lt;/p&gt;

&lt;p&gt;Besides having to build out the networking, routing, security, and worker nodes separately from the managed master nodes, there’s no longer any bundled support for storage starting from 1.23, and the existing support for external load balancers is limited.&lt;/p&gt;

&lt;p&gt;This tutorial, presented in separate parts, will demonstrate how to build out a robust Kubernetes cluster with just a few commands. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;EKS Cluster with support for OIDC&lt;/li&gt;
&lt;li&gt;Add Storage support: &lt;a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/" rel="noopener noreferrer"&gt;persistent volumes&lt;/a&gt; using &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AmazonEBS.html" rel="noopener noreferrer"&gt;EBS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add load balancer support: layer 4 (&lt;a href="https://aws.amazon.com/elasticloadbalancing/network-load-balancer/" rel="noopener noreferrer"&gt;NLB&lt;/a&gt;) and layer 7 (&lt;a href="https://aws.amazon.com/elasticloadbalancing/application-load-balancer/" rel="noopener noreferrer"&gt;ALB&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Add traffic security support: network policies using &lt;a href="https://www.tigera.io/project-calico/" rel="noopener noreferrer"&gt;Calico&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Demo application with &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; putting it all together&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to secure services that need access to cloud resources, an &lt;a href="https://openid.net/developers/how-connect-works/" rel="noopener noreferrer"&gt;OIDC provider&lt;/a&gt; through &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html" rel="noopener noreferrer"&gt;IAM Roles for Service Account&lt;/a&gt; facility will be used.&lt;/p&gt;

&lt;h2&gt;
  
  
  0. Prerequisites
&lt;/h2&gt;

&lt;p&gt;These are are some prerequisites and initial steps needed to get started before provisioning a Kubernetes cluster and installing add-ons.&lt;/p&gt;

&lt;h3&gt;
  
  
  0.1 Knowledge: Systems
&lt;/h3&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%2Faqzshuffp4kni7i9t487.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%2Faqzshuffp4kni7i9t487.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basic concepts of systems, such as Linux and the shell (redirection, pipes, process substitution, command substitution, environment variables), as well as virtualization and containers are useful. The concept of a service (daemon) is important.&lt;/p&gt;

&lt;h3&gt;
  
  
  0.2 Knowledge: Networking
&lt;/h3&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%2F5hd97akfkxxg8dzg26mh.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%2F5hd97akfkxxg8dzg26mh.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article requires some basic understanding of networking with TCP/IP and the OSI model, specifically the Transport Layer 4 and Application Layer 7 for HTTP. This article covers using load balancing and reverse proxy.&lt;/p&gt;

&lt;p&gt;In Kubernetes, familiarity with service types: ClusterIP, NodePort, LoadBalancer, ExternalName and the ingress resource are important.&lt;/p&gt;

&lt;p&gt;Exposure to other types of Kubernetes resource objects used in this guide are helpful: &lt;code&gt;persistentvolumeclaims&lt;/code&gt; (&lt;code&gt;pvc&lt;/code&gt;), &lt;code&gt;storageclass&lt;/code&gt; (&lt;code&gt;sc&lt;/code&gt;), &lt;code&gt;pods&lt;/code&gt;, &lt;code&gt;deployments&lt;/code&gt;, &lt;code&gt;statefulsets&lt;/code&gt; (&lt;code&gt;sts&lt;/code&gt;), &lt;code&gt;configmaps&lt;/code&gt;, &lt;code&gt;serviceaccount&lt;/code&gt; (&lt;code&gt;sa&lt;/code&gt;) and &lt;code&gt;networkpolicies&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  0.4 Tools
&lt;/h3&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%2F7u87et62nyhbwrksb29d.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%2F7u87et62nyhbwrksb29d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are the tools used in this article series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; [&lt;code&gt;aws&lt;/code&gt;] is a tool that interacts with AWS.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/reference/kubectl/" rel="noopener noreferrer"&gt;kubectl client&lt;/a&gt; [&lt;code&gt;kubectl&lt;/code&gt;] a the tool that can interact with the Kubernetes cluster. This can be installed using adsf tool.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;helm&lt;/a&gt; [&lt;code&gt;helm&lt;/code&gt;] is a tool that can install Kubernetes applications that are packaged as helm charts.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://eksctl.io/" rel="noopener noreferrer"&gt;eksctl&lt;/a&gt; [&lt;code&gt;eksctl&lt;/code&gt;] is the tool that can provision EKS cluster as well as supporting VPC network infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html" rel="noopener noreferrer"&gt;POSIX Shell&lt;/a&gt; [&lt;code&gt;sh&lt;/code&gt;] such as &lt;a href="https://www.gnu.org/software/bash/" rel="noopener noreferrer"&gt;bash&lt;/a&gt;[&lt;code&gt;bash&lt;/code&gt;] or &lt;a href="https://www.zsh.org/" rel="noopener noreferrer"&gt;zsh&lt;/a&gt; [&lt;code&gt;zsh&lt;/code&gt;] are used to run the commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools are highly recommended:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://asdf-vm.com/" rel="noopener noreferrer"&gt;adsf&lt;/a&gt; [&lt;code&gt;adsf&lt;/code&gt;] is a tool that installs versions of popular tools like kubectl.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jqlang.github.io/jq/" rel="noopener noreferrer"&gt;jq&lt;/a&gt; [&lt;code&gt;jq&lt;/code&gt;] is a tool to query and print JSON data&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gnu.org/software/grep/" rel="noopener noreferrer"&gt;GNU Grep&lt;/a&gt; [&lt;code&gt;grep&lt;/code&gt;] supports extracting string patterns using extended &lt;a href="https://en.wikipedia.org/wiki/Regular_expression" rel="noopener noreferrer"&gt;Regex&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions" rel="noopener noreferrer"&gt;PCRE&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  0.5 AWS Setup
&lt;/h3&gt;

&lt;p&gt;Before getting started on EKS, you will need to set up billing to an AWS account (there’s a free tier), and then configure a profile that has provides access to an IAM User identity. See Setting up the AWS CLI for more information on configuring a profile.&lt;/p&gt;

&lt;p&gt;After setup, you can test access with the following below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-profile-goes-here&amp;gt;"&lt;/span&gt;
aws sts get-caller-identity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like the following with values appropriate to your environment, e.g. example output to IAM user named &lt;code&gt;kwisatzhaderach&lt;/code&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%2Fuploads%2Farticles%2Fvqlvd4rpb6fj0763mwrj.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%2Fvqlvd4rpb6fj0763mwrj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  0.6 Kubernetes Client Setup
&lt;/h3&gt;

&lt;p&gt;If you use &lt;code&gt;asdf&lt;/code&gt; to install &lt;code&gt;kubectl&lt;/code&gt;, you can get the latest version with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install kubectl plugin for asdf&lt;/span&gt;
asdf plugin-add kubectl &lt;span class="se"&gt;\&lt;/span&gt;
  https://github.com/asdf-community/asdf-kubectl.git
asdf &lt;span class="nb"&gt;install &lt;/span&gt;kubectl latest

&lt;span class="c"&gt;# fetch latest kubectl &lt;/span&gt;
asdf &lt;span class="nb"&gt;install &lt;/span&gt;kubectl latest
asdf global kubectl latest

&lt;span class="c"&gt;# test results of latest kubectl &lt;/span&gt;
kubectl version &lt;span class="nt"&gt;--short&lt;/span&gt; &lt;span class="nt"&gt;--client&lt;/span&gt; 2&amp;gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Client Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1.27.1&lt;/span&gt;
&lt;span class="na"&gt;Kustomize Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v5.0.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, create directory to store Kubernetes configurations that will be used by the &lt;code&gt;KUBECONFIG&lt;/code&gt; env variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  0.7 Setup Environment Variables
&lt;/h3&gt;

&lt;p&gt;These environment variables will be used throughout this guide. If opening up a new browser tab, make sure to set the environment variables accordingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# variables used to create EKS&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;AWS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-aws-profile"&lt;/span&gt; &lt;span class="c"&gt;# CHANGEME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKS_CLUSTER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-unique-cluster-name"&lt;/span&gt; &lt;span class="c"&gt;# CHANGEME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKS_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EKS_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.26"&lt;/span&gt;
&lt;span class="c"&gt;# KUBECONFIG variable&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/&lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt;.&lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt;.yaml

&lt;span class="c"&gt;# account id&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws sts get-caller-identity &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"Account"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text
&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  1. Provision an EKS cluster
&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffu5ewlzhqd5qdgjdvfg9.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%2Ffu5ewlzhqd5qdgjdvfg9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After prerequisite tools are installed and setup, we can start provisioning cloud resources and deploy components to Kubernetes. &lt;/p&gt;

&lt;h3&gt;
  
  
  1.1. Provision the EKS Cluster
&lt;/h3&gt;

&lt;p&gt;The cluster can be brought up with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl create cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; &lt;span class="nv"&gt;$EKS_VERSION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--nodes&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, check the status of the worker nodes and applications running on Kubernetes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
kubectl get all &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like the following.&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%2Fhdlwkg7iospru75jpyki.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%2Fhdlwkg7iospru75jpyki.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2. Install the Kubernetes client
&lt;/h3&gt;

&lt;p&gt;Once this finished in about 20 minutes to provision both VPC and EKS, install a kubectl version that matches the Kubernetes server version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# fetch exact version of Kubernetes server (Requires GNU Grep)&lt;/span&gt;
&lt;span class="nv"&gt;VER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl version &lt;span class="nt"&gt;--short&lt;/span&gt; 2&amp;gt; /dev/null &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep &lt;/span&gt;Server &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oP&lt;/span&gt; &lt;span class="s1"&gt;'(\d{1,2}\.){2}\d{1,2}'&lt;/span&gt;
&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# setup kubectl tool&lt;/span&gt;
asdf &lt;span class="nb"&gt;install &lt;/span&gt;kubectl &lt;span class="nv"&gt;$VER&lt;/span&gt;
asdf global kubectl &lt;span class="nv"&gt;$VER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;NOTE&lt;/strong&gt;: The above command requires &lt;a href="https://www.gnu.org/software/grep/" rel="noopener noreferrer"&gt;GNU grep&lt;/a&gt;. If you have &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt;, you can run &lt;code&gt;brew install grep&lt;/code&gt;. Windows can get this with &lt;a href="https://www.msys2.org/" rel="noopener noreferrer"&gt;MSYS2&lt;/a&gt; or &lt;a href="https://git-scm.com/download/win" rel="noopener noreferrer"&gt;git-bash&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1.3 Add OIDC Provider Support
&lt;/h3&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%2Fgesyugb0faz6d5qxz8bf.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%2Fgesyugb0faz6d5qxz8bf.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The EKS cluster has an &lt;a href="https://openid.net/developers/how-connect-works/" rel="noopener noreferrer"&gt;OpenID Connect&lt;/a&gt; (&lt;a href="https://openid.net/developers/how-connect-works/" rel="noopener noreferrer"&gt;OIDC&lt;/a&gt;) issuer URL associated with it. To use &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html" rel="noopener noreferrer"&gt;IRSA&lt;/a&gt; (&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html" rel="noopener noreferrer"&gt;IAM roles for service accounts&lt;/a&gt;), an IAM OIDC provider must exist for the cluster’s OIDC issuer URL.&lt;/p&gt;

&lt;p&gt;You can set this up with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eksctl utils associate-iam-oidc-provider &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cluster&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--approve&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html" rel="noopener noreferrer"&gt;OIDC provider&lt;/a&gt; is added with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;OIDC_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws eks describe-cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$EKS_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$EKS_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"cluster.identity.oidc.issuer"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; text &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; 5
&lt;span class="si"&gt;)&lt;/span&gt;

aws iam list-open-id-connect-providers &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nv"&gt;$OIDC_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt; &lt;span class="nt"&gt;-f4&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="nt"&gt;-f4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AWS Cloud Resources
&lt;/h3&gt;

&lt;p&gt;These are some of the AWS resource objects used in this guide.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/eks/" rel="noopener noreferrer"&gt;Elastic Kubernetes Service&lt;/a&gt; (&lt;a href="https://aws.amazon.com/eks/" rel="noopener noreferrer"&gt;EKS&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/vpc/" rel="noopener noreferrer"&gt;Virtual Compute Cloud&lt;/a&gt; (&lt;a href="https://aws.amazon.com/vpc/" rel="noopener noreferrer"&gt;VPC&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/ec2/" rel="noopener noreferrer"&gt;Elastic Computer Cloud&lt;/a&gt; (&lt;a href="https://aws.amazon.com/ec2/" rel="noopener noreferrer"&gt;EC2&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html" rel="noopener noreferrer"&gt;AutoScale Group&lt;/a&gt; (&lt;a href="https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html" rel="noopener noreferrer"&gt;AGS&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html" rel="noopener noreferrer"&gt;Managed Node Groups&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This first article shows have to get a modern Kubernetes cluster working with support for OIDC that will allow restricted access to cloud resources from Kubernetes applications using concept of &lt;a href="https://wikipedia.org/wiki/Principle_of_least_privilege" rel="noopener noreferrer"&gt;least privilege&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article uses &lt;code&gt;eksctl&lt;/code&gt; tool to provision the necessary cloud resources to bring up EKS.  The &lt;code&gt;eksctl&lt;/code&gt; tool will use &lt;a href="https://aws.amazon.com/cloudformation/" rel="noopener noreferrer"&gt;Cloud Formation&lt;/a&gt; stacks to deploy the necessary cloud resources (VPC, EC2, SGs, etc) that make up the full solution.&lt;/p&gt;

&lt;p&gt;I am sure there are many wondering, why not use something like &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; for provisioning? &lt;/p&gt;

&lt;p&gt;That is actually a good idea except that this will be more involved because we'll have to deploy all of the components required to make a functional EKS cluster: VPC, internet gateways, nat groups, subnet, routing tables, auto-scale groups, security groups, etc. in addition to the master control plane (EKS).&lt;/p&gt;

&lt;p&gt;In the future, I would like to make a similar series with Terraform to setup the base EKS cluster, and then use &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; with &lt;a href="https://developer.hashicorp.com/terraform/language/functions/templatefile" rel="noopener noreferrer"&gt;templatefile&lt;/a&gt; or &lt;a href="https://tanzu.vmware.com/developer/guides/helmfile-what-is/" rel="noopener noreferrer"&gt;Helmfile&lt;/a&gt; to manage installing helm charts and kubernetes manifests.&lt;/p&gt;

&lt;p&gt;The ultimate goal of this series is to quickly get a robust and secure Kubernetes cluster with necessary features like storage and networking with preferably low complexity and friction.&lt;/p&gt;

&lt;p&gt;From here, we can explore other developments and tutorials on Kubernetes, such as o11y or observability (&lt;a href="https://grafana.com/oss/loki/" rel="noopener noreferrer"&gt;PLG&lt;/a&gt;, &lt;a href="https://www.elastic.co/what-is/elk-stack" rel="noopener noreferrer"&gt;ELK&lt;/a&gt;, &lt;a href="https://fluentbit.io/" rel="noopener noreferrer"&gt;ELF&lt;/a&gt;, &lt;a href="https://www.influxdata.com/blog/introduction-to-influxdatas-influxdb-and-tick-stack/" rel="noopener noreferrer"&gt;TICK&lt;/a&gt;, &lt;a href="https://www.jaegertracing.io/" rel="noopener noreferrer"&gt;Jaeger&lt;/a&gt;, &lt;a href="https://pyroscope.io/" rel="noopener noreferrer"&gt;Pyroscope&lt;/a&gt;), service mesh (&lt;a href="https://linkerd.io/" rel="noopener noreferrer"&gt;Linkerd&lt;/a&gt;, &lt;a href="https://istio.io/" rel="noopener noreferrer"&gt;Istio&lt;/a&gt;, &lt;a href="https://www.nginx.com/blog/introducing-nginx-service-mesh/" rel="noopener noreferrer"&gt;NSM&lt;/a&gt;, &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt;, &lt;a href="https://isovalent.com/blog/post/cilium-service-mesh/" rel="noopener noreferrer"&gt;Cillium&lt;/a&gt;), and progressive delivery (&lt;a href="https://argo-cd.readthedocs.io/" rel="noopener noreferrer"&gt;ArgoCD&lt;/a&gt;, &lt;a href="https://fluxcd.io/" rel="noopener noreferrer"&gt;FluxCD&lt;/a&gt;, &lt;a href="https://spinnaker.io/" rel="noopener noreferrer"&gt;Spinnaker&lt;/a&gt;).&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>awscloud</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Install Terraform with tfenv</title>
      <dc:creator>Joaquin Menchaca</dc:creator>
      <pubDate>Sun, 15 Jan 2023 18:36:35 +0000</pubDate>
      <link>https://dev.to/joachim8675309/install-terraform-with-tfenv-1cg2</link>
      <guid>https://dev.to/joachim8675309/install-terraform-with-tfenv-1cg2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fsplvh7lxc41upuigwrky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fsplvh7lxc41upuigwrky.png" alt="Image description" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There will come a time when you will need to change to different versions of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;.  Similar to tools like &lt;code&gt;rbenv&lt;/code&gt; for &lt;a href="https://www.ruby-lang.org" rel="noopener noreferrer"&gt;Ruby&lt;/a&gt; or &lt;code&gt;pyenv&lt;/code&gt; for &lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, there's a popular tool used to install different versions of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; called &lt;code&gt;tfenv&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Most tooling for infrastructure operations runs on Intel processors, called the &lt;code&gt;amd64&lt;/code&gt; architecture with in &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;, but given the recent addition of Macbook M1 laptops, the architecture is &lt;code&gt;arm64&lt;/code&gt;.  Older versions of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; that may be needed will require installing &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; that is only available on Intel processors (&lt;code&gt;amd64&lt;/code&gt; binaries).  This can be installed using &lt;code&gt;tfenv&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;This article will have cover the following sections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Installing &lt;code&gt;tfenv&lt;/code&gt; on Ubuntu (&lt;code&gt;linux&lt;/code&gt;) and mac OS (&lt;code&gt;darwin&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Installing a latest or recent version of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Installing legacy versions of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; on macOS with Arm processor (Macbook M1/M2)&lt;/li&gt;
&lt;li&gt;Installing Legacy providers plugins (Ubuntu and Macbook M1/M2)&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Installing tfenv
&lt;/h1&gt;

&lt;p&gt;Here's how you can install &lt;code&gt;tfenv&lt;/code&gt; on Ubuntu (&lt;code&gt;linux&lt;/code&gt;) or mac OS (&lt;code&gt;darwin&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing tfenv on Ubuntu
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/tfutils/tfenv.git &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/.tfenv
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.tfenv/bin:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c"&gt;# install to appropriate shell startup file, e.g. $HOME/.bashrc&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH="$HOME/.tfenv/bin:$PATH"'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/.profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing tfenv on mac OS
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;tfenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing Terraform
&lt;/h1&gt;

&lt;p&gt;Once &lt;code&gt;tfenv&lt;/code&gt; is installed and available in the path, you can simply run something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tfenv &lt;span class="nb"&gt;install &lt;/span&gt;1.3.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;tfenv list-remote&lt;/code&gt; you can fetch different versions of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; that are available for installation.  From there, you can use &lt;a href="https://www.gnu.org/software/grep/" rel="noopener noreferrer"&gt;GNU grep&lt;/a&gt; to select the desired version.  For example, here's how to install the latest version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;LATEST_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;tfenv list-remote &lt;span class="se"&gt;\&lt;/span&gt;
 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-vP&lt;/span&gt; &lt;span class="s1"&gt;'\d.\d{0,2}.\d{0,2}-.*'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;
&lt;span class="si"&gt;)&lt;/span&gt;

tfenv &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LATEST_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: On macOS, which has BSD flavor &lt;code&gt;grep&lt;/code&gt;, it doesn't support &lt;a href="https://www.pcre.org/" rel="noopener noreferrer"&gt;PCRE&lt;/a&gt;.  To get &lt;a href="https://www.gnu.org/software/grep/" rel="noopener noreferrer"&gt;GNU Grep&lt;/a&gt; with support for &lt;a href="https://www.pcre.org/" rel="noopener noreferrer"&gt;PCRE&lt;/a&gt;, use &lt;code&gt;brew install grep&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;You can extract the last minor version by passing in an explicit major version to &lt;a href="https://www.gnu.org/software/grep/" rel="noopener noreferrer"&gt;GNU Grep&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# find latest 0.12&lt;/span&gt;
&lt;span class="nv"&gt;LATEST_0_12&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;tfenv list-remote  &lt;span class="se"&gt;\&lt;/span&gt;
 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oP&lt;/span&gt; &lt;span class="s1"&gt;'^0.12.\d{1,2}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;--version-sort&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;
&lt;span class="si"&gt;)&lt;/span&gt;

tfenv &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;LATEST_0_12&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the latest version, whatever that is, you can also just run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tfenv &lt;span class="nb"&gt;install &lt;/span&gt;latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Using the desired Terraform version
&lt;/h1&gt;

&lt;p&gt;When you want to use the a particular version of an installed version &lt;code&gt;terraform&lt;/code&gt;, you can select it with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tfenv use 1.3.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, to have the &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; switch automatically when navigating to the project directory, you can place a &lt;code&gt;.terraform-version&lt;/code&gt; to auto-select the version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;  &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/my_project/.terraform-version
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'1.3.7'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/my_project/.terraform-version

&lt;span class="c"&gt;# change version of Terraform automatically&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/my_project/.terraform-version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing Legacy x64 versions on Mac
&lt;/h1&gt;

&lt;p&gt;If you Macbook sports a arm64 processor, you need to get &lt;a href="https://support.apple.com/en-us/HT211861" rel="noopener noreferrer"&gt;Rosetta&lt;/a&gt; to run &lt;code&gt;amd64&lt;/code&gt; binaries on macOS.  Afterward, you can follow these steps below to install legacy versions of &lt;code&gt;terraform&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TFENV_ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"amd64"&lt;/span&gt;

&lt;span class="c"&gt;# install amd64 terrafrom version since there are no arm64 binaries&lt;/span&gt;
tfenv &lt;span class="nb"&gt;install &lt;/span&gt;0.12.31
tfenv use 0.12.31
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Installing Legacy providers
&lt;/h1&gt;

&lt;p&gt;In recent versions of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;, this installation will happen automatically when you run &lt;code&gt;terraform init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;First, you need to find the appropriate plugin version that matches the supported version of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;.  In the case of &lt;code&gt;terraform-provider-kubectl&lt;/code&gt;, you need to install &lt;code&gt;1.11.2&lt;/code&gt; of that version of that plugin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing legacy provider on Ubuntu Linux
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"linux_amd64"&lt;/span&gt;
&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.11.2"&lt;/span&gt;
&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"terraform-provider-kubectl_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zip"&lt;/span&gt;
&lt;span class="nv"&gt;REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gavinbunney/terraform-provider-kubectl"&lt;/span&gt;
&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REPO&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/releases/download/v&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# setup plugins directory if this does not exist already&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/.terraform.d/plugins/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/

&lt;span class="c"&gt;# download archive and install plugin&lt;/span&gt;
&lt;span class="nb"&gt;pushd&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/Downloads
curl &lt;span class="nt"&gt;-sOL&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
unzip &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm &lt;/span&gt;README.md LICENSE
&lt;span class="nb"&gt;mv &lt;/span&gt;terraform-provider-kubectl_v&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/.terraform.d/plugins/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/
&lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing legacy provider on Macbook M1
&lt;/h2&gt;

&lt;p&gt;For current Macbooks running the arm64 processor, you will need to install the legacy provider for amd64 (not arm64).  This is how you can do that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"darwin_amd64"&lt;/span&gt; &lt;span class="c"&gt;# install amd64 plugin for legacy terraform &lt;/span&gt;
&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.11.2"&lt;/span&gt;
&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"terraform-provider-kubectl_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.zip"&lt;/span&gt;
&lt;span class="nv"&gt;REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gavinbunney/terraform-provider-kubectl"&lt;/span&gt;
&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;REPO&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/releases/download/v&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# setup plugins directory if this does not exist already&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.terraform.d/plugins/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/

&lt;span class="c"&gt;# download archive&lt;/span&gt;
&lt;span class="nb"&gt;pushd&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/Downloads
curl &lt;span class="nt"&gt;-sOL&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
unzip &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PKG&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm &lt;/span&gt;README.md LICENSE
&lt;span class="nb"&gt;mv &lt;/span&gt;terraform-provider-kubectl_v&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/.terraform.d/plugins/&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/
&lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope this is useful to your &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; adventures.  The reason why locking down versions of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; is important, is that there are significant language changes that make the code incompatible.  The installer dependency chain with &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt; modules and providers will need to match the target version of the &lt;code&gt;terraform&lt;/code&gt; command.  &lt;/p&gt;

&lt;p&gt;In addition to this, the state that is generated from interacting with the provider will likely need to match, so it is important that the infrastructure that created with a particular version of &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;, also be removed when ultimately &lt;code&gt;terraform destroy&lt;/code&gt; is used.&lt;/p&gt;

&lt;p&gt;As the infrastructure progresses forward, there are techniques you can use to smoothly transition.  One method it to have modular modules that depend on looking up the state in the cloud through data sources, and important existing infrastructure into the state using &lt;code&gt;terraform import&lt;/code&gt;.  This is definitely material for a future article.&lt;/p&gt;

&lt;p&gt;In the meantime, you can use the supported version with tools like &lt;code&gt;tfenv&lt;/code&gt;.  Another tool, as an alternative to &lt;code&gt;tfenv&lt;/code&gt; is &lt;a href="https://asdf-vm.com/" rel="noopener noreferrer"&gt;asdf&lt;/a&gt;.  I have not explored supported legacy amd64 legacy binaries on Macbook M1 yet, but assume this can work.  The &lt;a href="https://asdf-vm.com/" rel="noopener noreferrer"&gt;asdf&lt;/a&gt; is nice in that it has a plugin architecture to support a variety of languages.&lt;/p&gt;

&lt;p&gt;Lastly, about this article, which I am sure might unnerve shell purists, where I use &lt;code&gt;$HOME&lt;/code&gt; instead of &lt;code&gt;~&lt;/code&gt; and I use of curly braces for &lt;code&gt;${VARIABLES}&lt;/code&gt;, when they are not needed, when simply &lt;code&gt;$VARIABLE&lt;/code&gt; is preferred: this was done intentionally to make the variables light up in color syntax highlighters on different platforms, and &lt;code&gt;$HOME&lt;/code&gt; was used for novice uses that may not be familiar with &lt;code&gt;~&lt;/code&gt; notation.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>GKE with Consul Service Mesh</title>
      <dc:creator>Joaquin Menchaca</dc:creator>
      <pubDate>Sun, 04 Dec 2022 01:05:02 +0000</pubDate>
      <link>https://dev.to/joachim8675309/gke-with-consul-service-mesh-52hm</link>
      <guid>https://dev.to/joachim8675309/gke-with-consul-service-mesh-52hm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.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%2Fdw9bhj4gs5yw3ykqg6iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdw9bhj4gs5yw3ykqg6iw.png" alt="Article Header" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article shows how to set up and get started with &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;CCSM&lt;/a&gt; (&lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect service mesh&lt;/a&gt;) or more recently called just Consul Service Mesh.&lt;/p&gt;

&lt;p&gt;This article will cover how to install and configure services to use &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;CCSM&lt;/a&gt;. An example application &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt;, a distributed graph database, will be used as this demonstrates a real world application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📔 NOTE: This was tested on following below 
and may not work if versions are significantly 
different.

* Kubernetes API v1.22
* gcloud 402.0.0
* gsutil 5.13
* kubectl v1.22
* kustomize v4.5.4
* helm v3.8.2
* helmfile v0.144.0
* Docker 20.10.17
* Dgraph v21.03.2
* Consul 1.13.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  About Consul
&lt;/h2&gt;

&lt;p&gt;Consul is a popular tool for &lt;a href="https://en.wikipedia.org/wiki/Service_discovery" rel="noopener noreferrer"&gt;service discovery&lt;/a&gt; and a &lt;a href="https://en.wikipedia.org/wiki/Key%E2%80%93value_database" rel="noopener noreferrer"&gt;key-value store&lt;/a&gt; that was released in April-2014.&lt;/p&gt;

&lt;p&gt;Service discovery is important for clusters members or microservices as it provides “&lt;em&gt;automatic detection of devices and services offered by these devices on a computer network&lt;/em&gt; (&lt;a href="https://en.wikipedia.org/wiki/Service_discovery" rel="noopener noreferrer"&gt;ref&lt;/a&gt;)”. This allows “&lt;em&gt;applications and microservices locate different components on a network&lt;/em&gt; (&lt;a href="https://middleware.io/blog/service-discovery/" rel="noopener noreferrer"&gt;ref&lt;/a&gt;)”.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Key%E2%80%93value_database" rel="noopener noreferrer"&gt;key-value store&lt;/a&gt; is a network database to store &lt;a href="https://en.wikipedia.org/wiki/Hash_table" rel="noopener noreferrer"&gt;hash maps&lt;/a&gt; (also called &lt;a href="https://en.wikipedia.org/wiki/Associative_array" rel="noopener noreferrer"&gt;associative arrays&lt;/a&gt; or &lt;a href="https://realpython.com/python-dicts/" rel="noopener noreferrer"&gt;dictionaries&lt;/a&gt;). This allows services create and retrieve configuration.&lt;/p&gt;

&lt;p&gt;Building upon this, &lt;a href="https://www.hashicorp.com/" rel="noopener noreferrer"&gt;Hashicorp&lt;/a&gt; developed &lt;a href="https://github.com/hashicorp/consul-template" rel="noopener noreferrer"&gt;consul-template&lt;/a&gt;, which is essentially cloud native change configuration, and &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt;, now called &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Service Mesh&lt;/a&gt;, which can automatically inject side-car proxy containers into your network, so that services can communicate securely.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Service Mesh
&lt;/h2&gt;

&lt;p&gt;A service mesh uses automation to secure internal network traffic between member nodes. It does this by inserting reverse-proxy sidecar containers to every pod that is apart of the service mesh.&lt;/p&gt;

&lt;p&gt;With a network of side-car proxies installed, the traffic can be further secured using strict &lt;a href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/" rel="noopener noreferrer"&gt;mTLS&lt;/a&gt;, where not only the client must authenticate the validity of the server, but the server must authenticate the validity of the client. This is on top of the encryption of traffic between all the members of the mesh.&lt;/p&gt;

&lt;p&gt;A service mesh is divided into three planes (illustration below): &lt;em&gt;control plane&lt;/em&gt; to manage the overall service mesh, a data plane that consists of the members within the mesh that are secured with a proxy, and &lt;em&gt;observability plane&lt;/em&gt; to monitor traffic from within the mesh.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fsg99m2mgkl6y8gnfipqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fsg99m2mgkl6y8gnfipqw.png" alt="Consul Service Mesh: Control Plane, Data Plane, Observability Plane" width="800" height="777"&gt;&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;📔 NOTE: Observability is not supported for Consul Service 
Mesh with services that use multiple-ports.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; leverages off of &lt;a href="https://www.consul.io/" rel="noopener noreferrer"&gt;Consul&lt;/a&gt; to manage the connectivity through use of service discovery, health checks, and a service catalog. &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; is the default proxy that is injected into each of the pods to create the service mesh. This proxy can be swapped for another proxy component, such as &lt;a href="http://www.haproxy.org/" rel="noopener noreferrer"&gt;HAProxy&lt;/a&gt; or &lt;a href="http://nginx.org/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;These are the requirements to use this solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accounts
&lt;/h3&gt;

&lt;p&gt;No commercial licenses are needed for either &lt;a href="https://www.consul.io/" rel="noopener noreferrer"&gt;Consul&lt;/a&gt; and &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt;. All of the tools are accessible from the public Internet. For creating resources on &lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt;, you will need to create an account.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt; account with ownership of a project where you can deploy resources (where billing account was linked to the project)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Knowledge
&lt;/h3&gt;

&lt;p&gt;You should be familiar or have exposure to the following concepts to get more thorough understanding of this tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Virtual_hosting" rel="noopener noreferrer"&gt;virtual hosting&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Reverse_proxy" rel="noopener noreferrer"&gt;reverse-proxy&lt;/a&gt;, and &lt;a href="https://www.f5.com/services/resources/glossary/load-balancer" rel="noopener noreferrer"&gt;load balancer&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.techtarget.com/searchnetworking/definition/OSI" rel="noopener noreferrer"&gt;Layer 4 vs Layer 7 (OSI)&lt;/a&gt;, &lt;a href="https://www.cloudflare.com/learning/ddos/glossary/tcp-ip/" rel="noopener noreferrer"&gt;TCP/IP&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/IP_routing" rel="noopener noreferrer"&gt;routing&lt;/a&gt;, &lt;a href="https://www.gartner.com/en/information-technology/glossary/gateway" rel="noopener noreferrer"&gt;gateway&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.digitalocean.com/community/tutorials/http-1-1-vs-http-2-what-s-the-difference" rel="noopener noreferrer"&gt;HTTP/1.1 vs HTTP/2&lt;/a&gt; and &lt;a href="https://grpc.io/docs/what-is-grpc/core-concepts/" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.aquasec.com/cloud-native-academy/container-security/container-images/" rel="noopener noreferrer"&gt;images&lt;/a&gt; vs &lt;a href="https://www.docker.com/resources/what-container/" rel="noopener noreferrer"&gt;containers&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.vmware.com/topics/glossary/content/virtual-machine.html" rel="noopener noreferrer"&gt;virtual machines instances&lt;/a&gt; (&lt;a href="https://kubernetes.io/docs/concepts/architecture/nodes/" rel="noopener noreferrer"&gt;nodes&lt;/a&gt;) vs &lt;a href="https://kubernetes.io/docs/concepts/containers/" rel="noopener noreferrer"&gt;containers&lt;/a&gt; vs &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/" rel="noopener noreferrer"&gt;pods&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;, experience with deploying applications with &lt;code&gt;service&lt;/code&gt; resources is useful, but even if you don’t have this, this guide will walk you through it. Configuring &lt;code&gt;KUBECONFIG&lt;/code&gt; to access the &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; cluster with Kubernetes client (&lt;code&gt;kubectl&lt;/code&gt;) and using &lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; (&lt;code&gt;helm&lt;/code&gt;), so familiarity to this is useful.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt;, you should be familiar &lt;a href="https://cloud.google.com/sdk" rel="noopener noreferrer"&gt;Google Cloud SDK&lt;/a&gt; (&lt;code&gt;gcloud&lt;/code&gt; tool) with setting up an account, project, and provisioning resources. This is important as there are cost factors involved in setting these things up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools (Required)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F68talvtkwlpbfvs35qit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F68talvtkwlpbfvs35qit.png" alt="icons of required tools" width="800" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/sdk" rel="noopener noreferrer"&gt;Google Cloud SDK&lt;/a&gt; (&lt;code&gt;gcloud&lt;/code&gt; command) to interact with Google Cloud&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/tasks/tools/#kubectl" rel="noopener noreferrer"&gt;Kubernetes client&lt;/a&gt; (&lt;code&gt;kubectl&lt;/code&gt; command) to interact with Kubernetes&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; (&lt;code&gt;helm&lt;/code&gt; command) to install Kubernetes packages&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/databus23/helm-diff" rel="noopener noreferrer"&gt;helm-diff&lt;/a&gt; plugin to see differences about what will be deployed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/helmfile/helmfile" rel="noopener noreferrer"&gt;helmfile&lt;/a&gt; (&lt;code&gt;helmfile&lt;/code&gt; command) to automate installing many helm charts&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kustomize.io/" rel="noopener noreferrer"&gt;Kustomize&lt;/a&gt; (&lt;code&gt;kustomize&lt;/code&gt; command) to apply patches to existing Helm charts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tools (Recommended)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fem2jzma59t1nifjd00de.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fem2jzma59t1nifjd00de.png" alt="icons of optional tools" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These tools are useful in using the automation used form within this article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html" rel="noopener noreferrer"&gt;POSIX shell&lt;/a&gt; (sh) such as &lt;a href="https://www.gnu.org/software/bash/" rel="noopener noreferrer"&gt;GNU Bash&lt;/a&gt; (bash) or &lt;a href="https://www.zsh.org/" rel="noopener noreferrer"&gt;Zsh&lt;/a&gt; (zsh): these scripts in this guide were tested using either of these shells on macOS and Ubuntu Linux.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gnu.org/software/sed/" rel="noopener noreferrer"&gt;GNU stream-editor&lt;/a&gt; (sed) and &lt;a href="https://www.gnu.org/software/grep/" rel="noopener noreferrer"&gt;GNU grep&lt;/a&gt; (grep): scripts were tested with these tools. Note that BSD versions of these tools may NOT WORK, such as tools bundled with macOS or BSD.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;Docker Engine&lt;/a&gt; (docker command) to automate building and pushing running pydgraph client to Google container registry.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;git&lt;/a&gt; (git command) to download source code from git code repositories.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Setup
&lt;/h2&gt;

&lt;p&gt;This will setup all the content for this tutorial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Directory Structure
&lt;/h3&gt;

&lt;p&gt;The directory structure should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/projects/consul_connect
├── consul
│   └── helmfile.yaml
└── examples
    └── dgraph
        ├── helmfile.yaml
        └── pydgraph_client.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;a href="https://www.gnu.org/software/bash/" rel="noopener noreferrer"&gt;GNU Bash&lt;/a&gt;, you can create the above structure like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PROJECT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/projects/consul_connect
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_DIR&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;examples/dgraph,consul&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_DIR&lt;/span&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;consul,examples/dgraph&lt;span class="o"&gt;}&lt;/span&gt;/helmfile.yaml &lt;span class="se"&gt;\&lt;/span&gt;
 examples/dgraph/pydgraph_client.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Environment Variables
&lt;/h3&gt;

&lt;p&gt;These environment variables will be used in this project. Create a file called &lt;code&gt;env.sh&lt;/code&gt; with the contents below, changing values as appropriate, and then run &lt;code&gt;source env.sh&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# gke&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GKE_PROJECT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-gke-project"&lt;/span&gt; &lt;span class="c"&gt;# CHANGE ME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GKE_CLUSTER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"csm-demo"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GKE_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"us-central1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GKE_SA_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gke-worker-nodes-sa"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GKE_SA_EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GKE_SA_NAME&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GKE_PROJECT_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.iam.gserviceaccount.com"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.kube/&lt;span class="nv"&gt;$GKE_REGION&lt;/span&gt;-&lt;span class="nv"&gt;$GKE_CLUSTER_NAME&lt;/span&gt;.yaml

&lt;span class="c"&gt;# other&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USE_GKE_GCLOUD_AUTH_PLUGIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ClOUD_BILLING_ACCOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;my-billing-account&amp;gt;"&lt;/span&gt; &lt;span class="c"&gt;# CHANGEME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Google Project Setup
&lt;/h3&gt;

&lt;p&gt;For this tutorial, we’ll need to setup a Google cloud &lt;a href="https://cloud.google.com/storage/docs/projects" rel="noopener noreferrer"&gt;project&lt;/a&gt; and provide access to allow use to create the necessary cloud resources. Here is an example of how you can set this up with &lt;code&gt;gcloud&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# enable billing and APIs for GKE project if not done already&lt;/span&gt;
gcloud projects create &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt;
gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt;
gcloud beta billing projects &lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--billing-account&lt;/span&gt; &lt;span class="nv"&gt;$ClOUD_BILLING_ACCOUNT&lt;/span&gt;
gcloud services &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="s2"&gt;"container.googleapis.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Provision Cloud Resources
&lt;/h2&gt;

&lt;p&gt;These instructions will create the necessary cloud resources for this project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Provision Google Kubernetes Engine cluster
&lt;/h3&gt;

&lt;p&gt;The steps below will allow you to bring up a &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; cluster with 3 worker nodes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📔 NOTE: This will deploy a robust 3 worker node Kubernetes 
cloud that is suitable for Consul.  This will create a 
principal identity (Google Service Account) with the minimal 
necessary privileges required to manage the Kubernetes nodes 
(GCE).

📔 NOTE: For production environments, you will want to 
explore further security measures, such as private cluster, 
to block access from the public Internet.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;env.sh

&lt;span class="c"&gt;#######################&lt;/span&gt;
&lt;span class="c"&gt;# GSA with least priv for GKE&lt;/span&gt;
&lt;span class="c"&gt;##########################################&lt;/span&gt;
&lt;span class="nv"&gt;ROLES&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  roles/logging.logWriter
  roles/monitoring.metricWriter
  roles/monitoring.viewer
  roles/stackdriver.resourceMetadata.writer
&lt;span class="o"&gt;)&lt;/span&gt;

gcloud iam service-accounts create &lt;span class="nv"&gt;$GKE_SA_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--display-name&lt;/span&gt; &lt;span class="nv"&gt;$GKE_SA_NAME&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt;

&lt;span class="c"&gt;# assign google service account to roles in GKE project&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;ROLE &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ROLES&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
 &lt;/span&gt;gcloud projects add-iam-policy-binding &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--member&lt;/span&gt; &lt;span class="s2"&gt;"serviceAccount:&lt;/span&gt;&lt;span class="nv"&gt;$GKE_SA_EMAIL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--role&lt;/span&gt; &lt;span class="nv"&gt;$ROLE&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;#######################&lt;/span&gt;
&lt;span class="c"&gt;# GKE with least priv. GSA + Workload Identity&lt;/span&gt;
&lt;span class="c"&gt;##########################################&lt;/span&gt;
gcloud container clusters create &lt;span class="nv"&gt;$GKE_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$GKE_REGION&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--num-nodes&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--service-account&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GKE_SA_EMAIL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--machine-type&lt;/span&gt; &lt;span class="s2"&gt;"e2-standard-2"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--enable-ip-alias&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--workload-pool&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt;&lt;span class="s2"&gt;.svc.id.goog"&lt;/span&gt;

&lt;span class="c"&gt;#######################&lt;/span&gt;
&lt;span class="c"&gt;# KUBECONFIG&lt;/span&gt;
&lt;span class="c"&gt;##########################################&lt;/span&gt;
gcloud container clusters get-credentials &lt;span class="nv"&gt;$GKE_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$GKE_REGION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can test access to the cluster as well as the components installed with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
kubectl get all &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another useful command to test a new cluster is to see how many resources are available and what is consumed in the new cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl top nodes
kubectl top pods &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy Kubernetes Resources
&lt;/h2&gt;

&lt;p&gt;This section covers deploying Kubernetes resources such as &lt;code&gt;Deployment&lt;/code&gt;, &lt;code&gt;StatefulSet&lt;/code&gt;, &lt;code&gt;ServiceAccount&lt;/code&gt;, &lt;code&gt;Service&lt;/code&gt;, and so on. This will cover installing the &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh, &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt;, and &lt;a href="https://github.com/darkn3rd/pydgraph-client/tree/consul" rel="noopener noreferrer"&gt;pydgraph-client&lt;/a&gt; to access &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; through the service mesh.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy Consul Connect service mesh
&lt;/h3&gt;

&lt;p&gt;This will deploy the &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; Service mesh. Save the following code below as &lt;code&gt;consul/helmfile.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# https://artifacthub.io/packages/helm/hashicorp/consul&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://helm.releases.hashicorp.com&lt;/span&gt;

&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;consul&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;consul&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/consul&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.49.0&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;global&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;consul&lt;/span&gt;
          &lt;span class="na"&gt;datacenter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dc1&lt;/span&gt;
          &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- if eq (env "CCSM_SECURITY_ENABLED") "true"&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
          &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;enableAutoEncrypt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;gossipEncryption&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;autoGenerate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;acls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;manageSystemACLs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- end&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
        &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;runAsNonRoot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="na"&gt;runAsUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
        &lt;span class="na"&gt;connectInject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;controller&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;ui&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Helm chart configuration values will install &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh with automatic injection enabled. When you deploy a pod with annotation of &lt;code&gt;consul.hashicorp.com/connect-inject: "true"&lt;/code&gt;, side-car containers will be installed to copy the consul binary into the container and setup and configure &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; proxy. The &lt;code&gt;service&lt;/code&gt; proxy resources will be used as a blueprint to register the service with Consul's service catalog and configure the &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; proxy.&lt;/p&gt;

&lt;p&gt;Run the following to deploy the service mesh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;env.sh
helmfile &lt;span class="nt"&gt;--file&lt;/span&gt; ./consul/helmfile.yaml apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check that everything is deployed with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all &lt;span class="nt"&gt;--namespace&lt;/span&gt; consul
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fgxq16v1h27h4n19q2u0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fgxq16v1h27h4n19q2u0e.png" alt="Consul Service Mesh services" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy Observability
&lt;/h3&gt;

&lt;p&gt;Currently observability is not supported with multi-port services like &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt;. Hopefully this will get fixed in the future.&lt;/p&gt;

&lt;p&gt;For further information, see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.consul.io/docs/k8s/connect#caveats-for-multi-port-pods" rel="noopener noreferrer"&gt;Caveats for Multi-port Pods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/hashicorp/consul-k8s/issues/1594" rel="noopener noreferrer"&gt;injection stack traces when deploying multi-port application&lt;/a&gt; (issue &lt;a href="https://github.com/hashicorp/consul-k8s/issues/1594" rel="noopener noreferrer"&gt;1594&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deploy Dgraph
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; is a distributed graph database communicates through both HTTP on port &lt;code&gt;8080&lt;/code&gt; and gRPC on port &lt;code&gt;9080&lt;/code&gt;. &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; uses the DQL (Dgraph Query Language) through either gRPC or HTTP, and can also use GraphQL with HTTP. &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; supports administrative operations using GraphQL or REST.&lt;/p&gt;

&lt;p&gt;For this reason, to fully use &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; on a service mesh, you have to use the recently added multi-port configuration with &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt;. This requires separating the single multi-port &lt;code&gt;service&lt;/code&gt; proxy into two separate &lt;code&gt;service&lt;/code&gt; proxies: one for gRPC (&lt;code&gt;9080&lt;/code&gt;) and one for HTTP (&lt;code&gt;8080&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Save the following helmfile config below as &lt;code&gt;examples/dgraph/helmfile.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# https://artifacthub.io/packages/helm/dgraph/dgraph/0.0.19&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://charts.dgraph.io&lt;/span&gt;
  &lt;span class="c1"&gt;# https://artifacthub.io/packages/helm/main/raw&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bedag&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://bedag.github.io/helm-charts/&lt;/span&gt;

&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Dgraph additional resources required to support Consul&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-extra&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bedag/raw&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;1.1.0&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-zero&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-alpha&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-alpha-grpc&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-alpha-grpc&lt;/span&gt;
            &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grpc-alpha&lt;/span&gt;
                &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9080&lt;/span&gt;
              &lt;span class="na"&gt;publishNotReadyAddresses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
              &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph&lt;/span&gt;
                &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-0.0.19&lt;/span&gt;
                &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpha&lt;/span&gt;
                &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;

  &lt;span class="c1"&gt;# Dgraph cluster with 2 x StatefulSet (3 Zero pods, 3 Alpha pods)&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph/dgraph&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.19&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dgraph/dgraph-extra&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v21.03.2&lt;/span&gt;
        &lt;span class="na"&gt;zero&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;extraAnnotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/connect-inject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;true'&lt;/span&gt;
            &lt;span class="c1"&gt;# disable transparent-proxy for multi-port services&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/transparent-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;false'&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/transparent-proxy-exclude-inbound-ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5080,7080"&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/transparent-proxy-exclude-outbound-ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5080,7080"&lt;/span&gt;
        &lt;span class="na"&gt;alpha&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;extraAnnotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/connect-inject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;true'&lt;/span&gt;
            &lt;span class="c1"&gt;# disable transparent-proxy for multi-port services&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/transparent-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;false'&lt;/span&gt;
            &lt;span class="c1"&gt;# use these registered consul services for different ports&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/connect-service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dgraph-dgraph-alpha,dgraph-dgraph-alpha-grpc'&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/connect-service-port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8080,9080'&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/transparent-proxy-exclude-inbound-ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5080,7080"&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/transparent-proxy-exclude-outbound-ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5080,7080"&lt;/span&gt;
          &lt;span class="na"&gt;configFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;config.yaml&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;security:&lt;/span&gt;
                &lt;span class="s"&gt;whitelist: {{ env "DG_ACCEPT_LIST" | default "0.0.0.0/0" | quote }}&lt;/span&gt;
    &lt;span class="c1"&gt;# patch existing resources using merge patches&lt;/span&gt;
    &lt;span class="na"&gt;strategicMergePatches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# add serviceAccountName to Alpha StatefulSet&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StatefulSet&lt;/span&gt;
        &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-alpha&lt;/span&gt;
        &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;serviceAccountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-alpha&lt;/span&gt;

      &lt;span class="c1"&gt;# add serviceAccountName to Zero StatefulSet&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StatefulSet&lt;/span&gt;
        &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-zero&lt;/span&gt;
        &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;serviceAccountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-zero&lt;/span&gt;

      &lt;span class="c1"&gt;# add label to Alpha headless service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
        &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-alpha-headless&lt;/span&gt;
          &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/service-ignore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;true'&lt;/span&gt;

      &lt;span class="c1"&gt;# add label to Zero headless service&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
        &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-zero-headless&lt;/span&gt;
          &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;consul.hashicorp.com/service-ignore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;true'&lt;/span&gt;

    &lt;span class="c1"&gt;# patch existing resource using jsonPatches&lt;/span&gt;
    &lt;span class="na"&gt;jsonPatches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# remove existing grpc port from serivce&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dgraph-dgraph-alpha&lt;/span&gt;
        &lt;span class="na"&gt;patch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;op&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;remove&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/spec/ports/1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helmfile config uses some advance features to make some necessary changes required by &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pre-install service accounts and new gRPC service all packaged up as &lt;code&gt;dgraph-extras&lt;/code&gt; chart&lt;/li&gt;
&lt;li&gt;render Dgraph resources with required annotations for consul&lt;/li&gt;
&lt;li&gt;apply patches to add Dgraph headless service labels that instructs Consul to ignore these services when is configures the proxies.&lt;/li&gt;
&lt;li&gt;remove gRPC port (&lt;code&gt;9080&lt;/code&gt;) from the Dgraph Alpha &lt;code&gt;service&lt;/code&gt;, as this was defined earlier as a separate gRPC &lt;code&gt;service&lt;/code&gt; with the &lt;code&gt;dgraph-extras&lt;/code&gt; chart.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; will inject &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; sidecar proxy containers. Dgraph Zero will get a sidecar for port &lt;code&gt;6080&lt;/code&gt;, while Dgraph Alpha will have two sidecar proxy containers per pod: one for gRPC at port &lt;code&gt;9080&lt;/code&gt; and another one for HTTP at port &lt;code&gt;8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When ready to deploy all of this, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;env.sh
helmfile &lt;span class="nt"&gt;--file&lt;/span&gt; ./examples/dgraph/helmfile.yaml apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check on the status using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all &lt;span class="nt"&gt;--namespace&lt;/span&gt; dgraph
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show something like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F5cd63h9qqy5gz3bqylty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F5cd63h9qqy5gz3bqylty.png" alt="Dgraph output" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You notice the extra containers per pod in the ready state, which are the &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; proxy sidecar containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy Pydgraph client
&lt;/h3&gt;

&lt;p&gt;The client is a small python script that can load data into &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; using gRPC, and the container also has some useful tools like &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;grpcurl&lt;/code&gt;, and &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Save the following below as &lt;code&gt;examples/dgraph/pydgraph_client.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repositories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# https://artifacthub.io/packages/helm/main/raw&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bedag&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://bedag.github.io/helm-charts/&lt;/span&gt;

&lt;span class="na"&gt;releases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
    &lt;span class="na"&gt;chart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bedag/raw&lt;/span&gt;
    &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;1.1.0&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
            &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
              &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
              &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
                &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;serviceAccountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
                  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
                    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;requiredEnv "DOCKER_REGISTRY"&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;/pydgraph-client:{{ env "BUILD_VERSION" | default "latest" }}&lt;/span&gt;
                    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
                    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                      &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- if eq (env "CCSM_ENABLED") "true"&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
                      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DGRAPH_ALPHA_SERVER&lt;/span&gt;
                        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
                      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DGRAPH_GRPC_SERVER&lt;/span&gt;
                        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt;
                      &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- else&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
                      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DGRAPH_ALPHA_SERVER&lt;/span&gt;
                        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;env "DGRAPH_RELEASE" | default "dgraph"&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;-dgraph-alpha.{{ env "DGRAPH_NS" | default "dgraph" }}.svc.cluster.local&lt;/span&gt;
                      &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- end&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
                    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                      &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                        &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;64Mi"&lt;/span&gt;
                        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8m"&lt;/span&gt;
                      &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                        &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;128Mi"&lt;/span&gt;
                        &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;25m"&lt;/span&gt;

          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
            &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
            &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterIP&lt;/span&gt;
              &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
                &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt;
              &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
    &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- if eq (env "CCSM_ENABLED") "true"&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
    &lt;span class="na"&gt;strategicMergePatches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
        &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
        &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pydgraph-client&lt;/span&gt;
        &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;consul.hashicorp.com/connect-inject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
                &lt;span class="na"&gt;consul.hashicorp.com/transparent-proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
                &lt;span class="na"&gt;consul.hashicorp.com/connect-service-upstreams&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
                  &lt;span class="s"&gt;{{ env "DGRAPH_RELEASE" | default "dgraph" }}-dgraph-alpha:8080,{{ env "DGRAPH_RELEASE" | default "dgraph" }}-dgraph-alpha-grpc:9080&lt;/span&gt;
    &lt;span class="pi"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;- end&lt;/span&gt; &lt;span class="pi"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When ready to deploy this, you can run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;env.sh
&lt;span class="c"&gt;# https://hub.docker.com/r/darknerd/pydgraph-client&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_REGISTRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;darknerd
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CCSM_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true
&lt;/span&gt;helmfile &lt;span class="nt"&gt;--file&lt;/span&gt; ./examples/dgraph/pydgraph_client.yaml apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the deployment with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all &lt;span class="nt"&gt;--namespace&lt;/span&gt; pydgraph-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should result in something similar to the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F0lkkt5mx6xhcf2kyhs54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0lkkt5mx6xhcf2kyhs54.png" alt="pydgraph client output" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Upstream Traffic
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; will set up a tunnel between the upstream ports specified in the annotation to the ports that are serviced by &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First remote into the client container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CLIENT_NS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"pydgraph-client"&lt;/span&gt;
&lt;span class="nv"&gt;PYDGRAPH_POD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$CLIENT_NS&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; name&lt;span class="si"&gt;)&lt;/span&gt;
kubectl &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-ti&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"pydgraph-client"&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nv"&gt;$CLIENT_NS&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PYDGRAPH_POD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One in the container, test that HTTP traffic is working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--silent&lt;/span&gt; localhost:8080/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For gRPC traffic, you can run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grpcurl &lt;span class="nt"&gt;-plaintext&lt;/span&gt; &lt;span class="nt"&gt;-proto&lt;/span&gt; api.proto &lt;span class="se"&gt;\&lt;/span&gt;
  localhost:9080 api.Dgraph/CheckVersion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, you can try loading data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 load_data.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--plaintext&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--alpha&lt;/span&gt; localhost:9080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--files&lt;/span&gt; ./sw.nquads.rdf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--schema&lt;/span&gt; ./sw.schema
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These should work through the tunnel that is configured by &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; using the &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; proxy side-cars.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dgraph Graphical Viewer: Ratel
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; hosts an online graphical viewer at &lt;a href="https://play.dgraph.io/" rel="noopener noreferrer"&gt;https://play.dgraph.io/&lt;/a&gt;. If you would like to access the data we deployed with &lt;code&gt;load_data.py&lt;/code&gt;, you can run this in a new terminal tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward svc/dgraph-dgraph-alpha &lt;span class="nt"&gt;-n&lt;/span&gt; dgraph 8080:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can you can point the connection configuration in &lt;a href="https://github.com/dgraph-io/ratel/" rel="noopener noreferrer"&gt;Ratel&lt;/a&gt; to &lt;a href="http://localhost:8080:" rel="noopener noreferrer"&gt;http://localhost:8080:&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2Asvl_LfGWZLVCcCn7aWNxug.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2Asvl_LfGWZLVCcCn7aWNxug.webp" alt="ratel url" width="800" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;Console&lt;/strong&gt; and select &lt;strong&gt;Query&lt;/strong&gt; and enter the following DQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;allofterms&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Star&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Wars&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;@filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ge&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="n"&gt;release_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"1980"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;release_date&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;revenue&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;running_time&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;director&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="n"&gt;starring&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Run&lt;/strong&gt; to see the results of the query:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AcfY85xGePSYe3lEddyuw4A.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AcfY85xGePSYe3lEddyuw4A.webp" alt="ratel query" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Consul User Interface
&lt;/h2&gt;

&lt;p&gt;The Consul UI can be accessed by running this command in a new terminal tab:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;env.sh
kubectl port-forward service/consul-ui &lt;span class="nt"&gt;--namespace&lt;/span&gt; consul 8500:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can access the Consul UI through &lt;a href="http://localhost:8500" rel="noopener noreferrer"&gt;http://localhost:8500&lt;/a&gt;. The Consul UI should look like this below with other services appearing after &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; and pydgraph-client were deployed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2A-kVtR1DymSyeGJOLQkhsGw.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2A-kVtR1DymSyeGJOLQkhsGw.webp" alt="consul ui" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you click on &lt;a href="https://github.com/darkn3rd/pydgraph-client/tree/consul" rel="noopener noreferrer"&gt;pydgraph-client&lt;/a&gt;, you can see the connections:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AZMLlrLGG50uCJnYyOwKrOA.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AZMLlrLGG50uCJnYyOwKrOA.webp" alt="consul ui connections" width="800" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleanup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Kubernetes Resources
&lt;/h3&gt;

&lt;p&gt;You can cleanup Kubernetes resources with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;env.sh

&lt;span class="c"&gt;# delete pydgraph-client&lt;/span&gt;
helmfile &lt;span class="nt"&gt;--file&lt;/span&gt; ./examples/dgraph/helmfile.yaml delete
kubectl delete namespace pydgraph-client

&lt;span class="c"&gt;# delete dgraph&lt;/span&gt;
helmfile &lt;span class="nt"&gt;--file&lt;/span&gt; ./examples/dgraph/helmfile.yaml delete
kubectl delete pvc &lt;span class="nt"&gt;--selector&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dgraph &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"dgraph"&lt;/span&gt;
kubectl delete namespace dgraph

&lt;span class="c"&gt;# delete consul&lt;/span&gt;
helmfile &lt;span class="nt"&gt;--file&lt;/span&gt; ./consul/helmfile.yaml delete
kubectl delete pvc &lt;span class="nt"&gt;--selector&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;consul &lt;span class="nt"&gt;--namespace&lt;/span&gt; &lt;span class="s2"&gt;"consul"&lt;/span&gt;
kubectl delete namespace consul
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is important to delete the consul namespace if you intend to deploy new version of &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh in the future. This is because there are secrets left behind that will break future installations, so deleting the namespace will avoid this scenario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Resources
&lt;/h3&gt;

&lt;p&gt;The Kubernetes cluster and the associated Google service account can be deleted with the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source &lt;/span&gt;env.sh

gcloud container clusters delete &lt;span class="nv"&gt;$GKE_CLUSTER_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt; &lt;span class="nv"&gt;$GKE_REGION&lt;/span&gt;

gcloud iam service-accounts delete &lt;span class="nv"&gt;$GKE_SA_EMAIL&lt;/span&gt; &lt;span class="nt"&gt;--project&lt;/span&gt; &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Addendum: Publishing Pygraph-Client Images
&lt;/h2&gt;

&lt;p&gt;If you would like to publish the &lt;a href="https://github.com/darkn3rd/pydgraph-client/tree/consul" rel="noopener noreferrer"&gt;pydgraph-client&lt;/a&gt; images to an alternative registry, you can run the following steps below.&lt;br&gt;
Download the source code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;pushd &lt;/span&gt;examples
git clone &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--branch&lt;/span&gt; &lt;span class="s2"&gt;"consul"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  git@github.com:darkn3rd/pydgraph-client.git
&lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Publishing to GCR
&lt;/h3&gt;

&lt;p&gt;If you wish to use &lt;a href="https://cloud.google.com/container-registry" rel="noopener noreferrer"&gt;Google Container Registry&lt;/a&gt;, you can run the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;pushd&lt;/span&gt; ./examples/pydgraph-client

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 1: Environment variables&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;env.sh
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GCR_PROJECT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-gcr-project"&lt;/span&gt;  &lt;span class="c"&gt;# CHANGE ME&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_REGISTRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"gcr.io/&lt;/span&gt;&lt;span class="nv"&gt;$GCR_PROJECT_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ClOUD_BILLING_ACCOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;my-cloud-billing-account&amp;gt;"&lt;/span&gt; &lt;span class="c"&gt;# CHANGEME&lt;/span&gt;

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 2: Create GCR project and enable GCR&lt;/span&gt;
&lt;span class="c"&gt;# NOTE: Best practices is to use a single project for store/retreive images&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
gcloud projects create &lt;span class="nv"&gt;$GCR_PROJECT_ID&lt;/span&gt;
gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project &lt;span class="nv"&gt;$GCR_PROJECT_ID&lt;/span&gt;
gcloud beta billing projects &lt;span class="nb"&gt;link&lt;/span&gt; &lt;span class="nv"&gt;$GCR_PROJECT_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--billing-account&lt;/span&gt; &lt;span class="nv"&gt;$ClOUD_BILLING_ACCOUNT&lt;/span&gt;
gcloud services &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="s2"&gt;"containerregistry.googleapis.com"&lt;/span&gt; &lt;span class="c"&gt;# Enable GCR API&lt;/span&gt;
gcloud config &lt;span class="nb"&gt;set &lt;/span&gt;project &lt;span class="nv"&gt;$GKE_PROJECT_ID&lt;/span&gt;

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 3: Build local image&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; pydgraph-client:latest &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 4: Publish Image to GCR&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
gcloud auth configure-docker
docker tag pydgraph-client:latest &lt;span class="nv"&gt;$DOCKER_REGISTRY&lt;/span&gt;/pydgraph-client:latest
docker push &lt;span class="nv"&gt;$DOCKER_REGISTRY&lt;/span&gt;/pydgraph-client:latest

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 5: Grant GCR read access to GKE containers&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
gsutil iam ch &lt;span class="se"&gt;\&lt;/span&gt;
  serviceAccount:&lt;span class="nv"&gt;$GKE_SA_EMAIL&lt;/span&gt;:objectViewer &lt;span class="se"&gt;\&lt;/span&gt;
  gs://artifacts.&lt;span class="nv"&gt;$GCR_PROJECT_ID&lt;/span&gt;.appspot.com

&lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Publising to DockerHub
&lt;/h3&gt;

&lt;p&gt;If you have an account on &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;DockerHub&lt;/a&gt;, you can publish it there with these steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;pushd&lt;/span&gt; ./examples/pydgraph-client

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 1: Environment variables&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
&lt;span class="nb"&gt;source &lt;/span&gt;env.sh
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_REGISTRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-docker-hub-account-goes-here&amp;gt;"&lt;/span&gt;

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 2: Build local image&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; pydgraph-client:latest &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;###################&lt;/span&gt;
&lt;span class="c"&gt;# STEP 3: Publish Image to DcokerHub&lt;/span&gt;
&lt;span class="c"&gt;#######################################&lt;/span&gt;
docker login &lt;span class="c"&gt;# IMPORTANT: use api-token not the actual password&lt;/span&gt;
docker tag pydgraph-client:latest &lt;span class="nv"&gt;$DOCKER_REGISTRY&lt;/span&gt;/pydgraph-client:latest
docker push &lt;span class="nv"&gt;$DOCKER_REGISTRY&lt;/span&gt;/pydgraph-client:latest

&lt;span class="nb"&gt;popd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;These are some resources and references that may be useful in using this solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consul Documentation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.consul.io/docs/k8s/connect#kubernetes-pods-with-multiple-ports" rel="noopener noreferrer"&gt;Kubernetes Pods with Multiple Ports&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.hashicorp.com/tutorials/consul/kubernetes-secure-agents" rel="noopener noreferrer"&gt;Secure Consul and Registered Service on Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.consul.io/docs/k8s/annotations-and-labels" rel="noopener noreferrer"&gt;Annotations and Labels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/consul/docs/connect/transparent-proxy" rel="noopener noreferrer"&gt;Enable Transparent Proxy Mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.hashicorp.com/blog/transparent-proxy-on-consul-service-mesh" rel="noopener noreferrer"&gt;Transparent Proxy on Consul Service Mesh&lt;/a&gt;, 2020-JUL-01&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.hashicorp.com/consul/docs/k8s/connect" rel="noopener noreferrer"&gt;How does Consul Service Mesh Work on Kubernetes?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gateways and Ingress
&lt;/h3&gt;

&lt;p&gt;These are links for north-south traffic into mesh.&lt;br&gt;
I have not tested these solutions yet&lt;/p&gt;

&lt;p&gt;These are links that cover integration of either ingress controllers or API gateways with Consul. This may be using Consul as a backend database or the &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📔 NOTE: I have not tested the content of this material, just 
documenting any material I find on the topic for later 
exploration.  If you find any useful material out there, 
please send me a note.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.getambassador.io/docs/edge-stack/latest/howtos/consul/" rel="noopener noreferrer"&gt;Amabassador Edge Stack integration with Consul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.consul.io/docs/api-gateway" rel="noopener noreferrer"&gt;Consul API Gateway&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hashicorp.com/blog/using-hashicorp-consul-with-kong-ingress-controller-for-kubernetes" rel="noopener noreferrer"&gt;Using HashiCorp Consul with Kong Ingress Controller for Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://traefik.io/blog/getting-started-traefik-proxy-and-hashicorp-consul/" rel="noopener noreferrer"&gt;Getting Started With Traefik Proxy and HashiCorp Consul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://doc.traefik.io/traefik/providers/consul/" rel="noopener noreferrer"&gt;Taefik Consul Provider configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kschoche/traefik-consul" rel="noopener noreferrer"&gt;traefik-consul walk-through&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/joatmon08/consul-k8s-ingress-controllers" rel="noopener noreferrer"&gt;consul ingress controllers&lt;/a&gt; integration with Traefik or Kong using terrafom&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dhiaayachi/eks-consul-ingressnginx" rel="noopener noreferrer"&gt;Consul on EKS using nginx as ingress (transparent mode)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Tracing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://discuss.hashicorp.com/t/consul-connect-integration-of-jaeger-in-kubernetes/4394" rel="noopener noreferrer"&gt;Consul connect integration of jaeger in Kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/hashicorp/consul-demo-tracing" rel="noopener noreferrer"&gt;Consul Service Mesh Tracing Demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/envoyproxy/envoy/tree/main/examples/jaeger-tracing" rel="noopener noreferrer"&gt;https://github.com/envoyproxy/envoy/tree/main/examples/jaeger-tracing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dgraph Documentation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dgraph.io/docs/query-language/graphql-fundamentals/" rel="noopener noreferrer"&gt;DQL Fundamentals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Helmfile
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/helmfile/helmfile" rel="noopener noreferrer"&gt;https://github.com/helmfile/helmfile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tanzu.vmware.com/developer/guides/helmfile-what-is/" rel="noopener noreferrer"&gt;What is Helmfile?&lt;/a&gt; by Paul Czarkowski (VMWare Tanzu Developer Center)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Blog Source Code
&lt;/h3&gt;

&lt;p&gt;This is some code that I developed when testing &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh solution.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blog Source Code&lt;/strong&gt;: &lt;a href="https://github.com/darkn3rd/blog_tutorials/tree/master/kubernetes/gke/service-mesh/consul-connect" rel="noopener noreferrer"&gt;https://github.com/darkn3rd/blog_tutorials/tree/master/kubernetes/gke/service-mesh/consul-connect&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/gRPC Greeter Application&lt;/strong&gt;: &lt;a href="https://github.com/darkn3rd/greeter" rel="noopener noreferrer"&gt;https://github.com/darkn3rd/greeter&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pydgraph-client w consul support&lt;/strong&gt;: &lt;a href="https://github.com/darkn3rd/pydgraph-client/tree/consul" rel="noopener noreferrer"&gt;https://github.com/darkn3rd/pydgraph-client/tree/consul&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;There you have it, a small (cough) overview how to get started with &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; Service Mesh. In particular, here some of the takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provisioning &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubenertes&lt;/a&gt; (&lt;a href="https://cloud.google.com/kubernetes-engine" rel="noopener noreferrer"&gt;GKE&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;(addendum) Provisioning &lt;a href="https://cloud.google.com/container-registry" rel="noopener noreferrer"&gt;GCR&lt;/a&gt; and publishing images to &lt;a href="https://cloud.google.com/container-registry" rel="noopener noreferrer"&gt;GCR&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Deploying &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; Service Mesh on &lt;a href="https://cloud.google.com/kubernetes-engine" rel="noopener noreferrer"&gt;GKE&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Deploying a server and a client with multiport support: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP" rel="noopener noreferrer"&gt;HTTP&lt;/a&gt; and &lt;a href="https://grpc.io/" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Testing &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP" rel="noopener noreferrer"&gt;HTTP&lt;/a&gt; traffic with &lt;code&gt;curl&lt;/code&gt; and &lt;a href="https://grpc.io/" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt; traffic with &lt;code&gt;gprcurl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Limitations and Challenges with current multi-port scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, here’s some extra takeaways beyond just using &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using &lt;a href="https://github.com/helmfile/helmfile" rel="noopener noreferrer"&gt;Helmfile&lt;/a&gt; to deploy &lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; charts with templated chart config values, where values and branch logic is set by env vars.&lt;/li&gt;
&lt;li&gt;Using &lt;a href="https://github.com/helmfile/helmfile" rel="noopener noreferrer"&gt;Helmfile&lt;/a&gt; to patch using &lt;a href="https://elatov.github.io/2021/08/using-kustomize/" rel="noopener noreferrer"&gt;Kustomize merge&lt;/a&gt; and &lt;a href="https://skryvets.com/blog/2019/05/15/kubernetes-kustomize-json-patches-6902/" rel="noopener noreferrer"&gt;JSON Patch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; raw chart to package Kubernetes manifests as templated values&lt;/li&gt;
&lt;li&gt;Introduction to &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; distributed graph database&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Challenges with Consul
&lt;/h3&gt;

&lt;p&gt;You may have noticed that &lt;a href="https://www.consul.io/" rel="noopener noreferrer"&gt;Consul&lt;/a&gt; is, dare I say, complex, beyond complex. The documentation is good, but perhaps maybe not all that well organized, with many missing things.&lt;/p&gt;

&lt;p&gt;The underlying tool &lt;a href="https://www.consul.io/" rel="noopener noreferrer"&gt;Consul&lt;/a&gt; is very powerful, and &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh on top of this tool is quite robust and extremely flexible where you can swap out the default CA for other solutions, like &lt;a href="https://www.vaultproject.io/" rel="noopener noreferrer"&gt;Vault&lt;/a&gt; CA, and swap out the &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; proxy for another solution, like &lt;a href="http://nginx.org/" rel="noopener noreferrer"&gt;NGINX&lt;/a&gt; or &lt;a href="http://www.haproxy.org/" rel="noopener noreferrer"&gt;HAProxy&lt;/a&gt;. For ingress into the cluster, you can use &lt;a href="https://developer.hashicorp.com/consul/docs/api-gateway" rel="noopener noreferrer"&gt;Consul API Gateway&lt;/a&gt;, or another API Gateway or an ingress controller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh has some challenges or limitations (see below) when you have a service that supports multiple ports.&lt;/p&gt;

&lt;h4&gt;
  
  
  Complexity
&lt;/h4&gt;

&lt;p&gt;I have experimented with other service meshes and I was able to get up to speed quickly: &lt;a href="https://linkerd.io/" rel="noopener noreferrer"&gt;Linkerd&lt;/a&gt; = 1 day, &lt;a href="https://istio.io/" rel="noopener noreferrer"&gt;Istio&lt;/a&gt; = 3 days, &lt;a href="https://www.nginx.com/products/nginx-service-mesh/" rel="noopener noreferrer"&gt;NGINX Service Mesh&lt;/a&gt; = 5 days, but &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh took at least 11 days to get off the ground. This is by far the most complex solution available.&lt;/p&gt;

&lt;h4&gt;
  
  
  Unable to Update
&lt;/h4&gt;

&lt;p&gt;If you need to update &lt;a href="https://www.consul.io/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; with a configuration change and use helm to update consul, the consul-server pods may not reach a healthy state. You may have to delete everything and recreate it from scratch.&lt;/p&gt;

&lt;p&gt;Apparently there’s some way to ameliorate this by adding &lt;code&gt;leave_on_terminate: true&lt;/code&gt; setting in the &lt;code&gt;server.extraConfig&lt;/code&gt; (&lt;a href="https://discuss.hashicorp.com/t/unstable-deployment-on-k8s-with-helm-chart/44411" rel="noopener noreferrer"&gt;ref&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Higher Memory Footprint
&lt;/h4&gt;

&lt;p&gt;Consul Connect service mesh has a higher memory footprint, so on a small cluster with &lt;code&gt;e5-medium&lt;/code&gt; nodes (2 vCPUs, 4 GB memory), you will only be able to support a maximum of 6 side-car proxies. In order to get an application like &lt;a href="https://dgraph.io/" rel="noopener noreferrer"&gt;Dgraph&lt;/a&gt; working, which will have 6 nodes (3 Dgraph Alpha pods and 3 Dgraph Zero pods) for high availability along with at least one client, a larger footprint with more robust &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; worker nodes were required.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requirement for Service Resource
&lt;/h4&gt;

&lt;p&gt;One challenge to &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh is that it configures the &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; side-car proxy based on what you specify for a &lt;code&gt;service&lt;/code&gt;. This added some challenges.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A pure client that is not listening on a port, still requires you to specify a &lt;code&gt;service&lt;/code&gt; resource so that it can be added to the service mesh.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;StatefulSet&lt;/code&gt; that requires specifying a headless &lt;code&gt;service&lt;/code&gt; in addition to &lt;code&gt;service&lt;/code&gt; endpoint into the cluster will fail spectacularly if both service and headless service use the same port.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The docs explicitly note this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: As of consul-k8s &lt;code&gt;v0.26.0&lt;/code&gt; and Consul Helm &lt;code&gt;v0.32.0&lt;/code&gt;, having a Kubernetes service is &lt;strong&gt;required&lt;/strong&gt; to run services on the Consul Service Mesh.&lt;/em&gt; (&lt;a href="https://developer.hashicorp.com/consul/docs/k8s/connect#accepting-inbound-connections" rel="noopener noreferrer"&gt;ref&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  More Complexity with Multiport
&lt;/h4&gt;

&lt;p&gt;The Kubernetes &lt;code&gt;service&lt;/code&gt; API supports an array of &lt;code&gt;ports&lt;/code&gt; that you can specify, but &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; only supports a single port for &lt;a href="https://www.hashicorp.com/blog/transparent-proxy-on-consul-service-mesh" rel="noopener noreferrer"&gt;transparent-proxy&lt;/a&gt; mode. This is very bizarre, because a service with multiple ports is quite common, such as an admin port vs API port, or scenarios where a service has both HTTP and gRPC interfaces.&lt;/p&gt;

&lt;p&gt;This is also part of the Kubernetes &lt;code&gt;service&lt;/code&gt; API specification, which &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; reads to configure the &lt;a href="https://www.envoyproxy.io/" rel="noopener noreferrer"&gt;Envoy&lt;/a&gt; proxy. So, in this sense, &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; is not fully supported as far a parity with the &lt;code&gt;service&lt;/code&gt; API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F55qrokru98zv74dg0b3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F55qrokru98zv74dg0b3s.png" alt="Consul SM vs Other SM with multiport" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the &lt;a href="https://developer.hashicorp.com/consul/docs/k8s/connect#kubernetes-pods-with-multiple-ports" rel="noopener noreferrer"&gt;multi-port&lt;/a&gt; scenario, the following will need to be done on the server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;all &lt;code&gt;services&lt;/code&gt; with multiple ports will need to be broken up into separate services with only one port&lt;/li&gt;
&lt;li&gt;need to specify &lt;code&gt;consul.hashicorp.com/connect-service&lt;/code&gt; annotation listing each of the services supported that will be mapped into consul.&lt;/li&gt;
&lt;li&gt;need to specify &lt;code&gt;consul.hashicorp.com/connect-service-port annotation&lt;/code&gt; listing ports that correspond to the previous above annotation&lt;/li&gt;
&lt;li&gt;if ACLs are enabled, a &lt;code&gt;serviceaccount&lt;/code&gt; needs to be specified corresponding to each &lt;code&gt;service&lt;/code&gt; specified.&lt;/li&gt;
&lt;li&gt;if ACLs are enabled and Kubernetes 1.24+ is used, a corresponding &lt;code&gt;secret&lt;/code&gt; for the service token needs to be created as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The client will need the following in order to connect to the server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;specify &lt;code&gt;consul.hashicorp.com/connect-service-upstreams&lt;/code&gt; annotation listing the consul service and outbound port to use from &lt;code&gt;localhost&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;if ACLs are enabled, a &lt;code&gt;serviceaccount&lt;/code&gt; that corresponds to the &lt;code&gt;service&lt;/code&gt; specified for the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The client is now required to connect to &lt;code&gt;localhost&lt;/code&gt; at the target outbound port, not to the service endpont DNS name, such as &lt;code&gt;mysvc.myns.svc.cluster.local&lt;/code&gt;. This will be the only way to use the service mesh. Directly connecting to the service endpoint, e.g. &lt;code&gt;mysvc.myns.svc.cluster.local&lt;/code&gt;, will bypass the service mesh and thus will not be protected with encryption.&lt;/p&gt;

&lt;h4&gt;
  
  
  Insecurity with Multiport
&lt;/h4&gt;

&lt;p&gt;When &lt;a href="https://developer.hashicorp.com/consul/docs/connect/transparent-proxy" rel="noopener noreferrer"&gt;transparent-proxy&lt;/a&gt; is enabled, members can communicate using the DNS of the service endpoint, for example: &lt;code&gt;mysvc.myns.svc.cluster.local&lt;/code&gt;. And when you use &lt;a href="https://developer.hashicorp.com/consul/docs/k8s/connect#kubernetes-pods-with-multiple-ports" rel="noopener noreferrer"&gt;multi-port&lt;/a&gt; scenario, &lt;a href="https://www.hashicorp.com/blog/transparent-proxy-on-consul-service-mesh" rel="noopener noreferrer"&gt;transparent-proxy&lt;/a&gt; is unfortunately disabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fqd1540dpckrby8kgeite.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fqd1540dpckrby8kgeite.png" alt="Consul SM vs other SM for security" width="800" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of this situation, security through &lt;a href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/" rel="noopener noreferrer"&gt;mTLS&lt;/a&gt; or &lt;a href="https://developer.hashicorp.com/consul/docs/security/acl" rel="noopener noreferrer"&gt;ACLs&lt;/a&gt; (tokens) can be bypassed completely when multi-port services are configured. Any non-mesh member or mesh member that does not have access granted (through configuring an intention) can connect to the service endpoint, such as &lt;code&gt;mysvc.myns.svc.cluster.local&lt;/code&gt;. The only thing ACLs offer at this point is blocking encrypted traffic through the mesh, and thus the ACL feature is pointless.&lt;/p&gt;

&lt;p&gt;This issue can be ameliorated by configuring the service itself to only communicate through &lt;code&gt;localhost&lt;/code&gt;, which forces it to use the service mesh, but then this poses problems, such as trying to use an &lt;code&gt;ingress&lt;/code&gt;. Alternatively, you could use a firewall, such as a network policy. Ultimately, another non-Consul solution is needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ingress Challenge with Multiport
&lt;/h4&gt;

&lt;p&gt;An ingress controller is an interesting challenge to integrate to the service mesh, as annotations will be needed to put the ingress controller pods onto the service mesh. The ingress controller will route traffic to the backend &lt;code&gt;service&lt;/code&gt; using the local DNS, such as &lt;code&gt;mysvc.myns.svc.cluster.local&lt;/code&gt;, where the &lt;code&gt;service&lt;/code&gt; named &lt;code&gt;mysvc&lt;/code&gt; running in the &lt;code&gt;myns&lt;/code&gt; namespace.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://developer.hashicorp.com/consul/docs/k8s/connect#kubernetes-pods-with-multiple-ports" rel="noopener noreferrer"&gt;multi-port&lt;/a&gt; scenario however, this will not work, because the ingress controller is now required to route to &lt;code&gt;localhost&lt;/code&gt; for a specific outbound ports that are specified in the &lt;code&gt;consul.hashicorp.com/connect-service-upstreams&lt;/code&gt; annotation. The normal &lt;code&gt;ingress&lt;/code&gt; resource API does not support this setup, as it routes to Kubernetes &lt;code&gt;service&lt;/code&gt; DNS name, not to &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There may be some ingress controllers that may provide extra non-standard configurations that could support this requirement to route to &lt;code&gt;localhost&lt;/code&gt;, but unfortunately no one at &lt;a href="https://www.hashicorp.com/" rel="noopener noreferrer"&gt;Hashicorp&lt;/a&gt; has even tested this common use case (&lt;a href="https://github.com/hashicorp/consul-k8s/issues/1606" rel="noopener noreferrer"&gt;ref&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  No Observability with Multport
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F3448i209nk0fbri4il8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F3448i209nk0fbri4il8u.png" alt="Observability Tool Icons" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are using &lt;a href="https://developer.hashicorp.com/consul/docs/k8s/connect#kubernetes-pods-with-multiple-ports" rel="noopener noreferrer"&gt;multi-port&lt;/a&gt; scenario, observability is not an option. Just forget you even heard of the word observability, one of the three planes that make up the service mesh solution. The &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; injection process will actually cause stack traces.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/hashicorp/consul-k8s/issues/1594" rel="noopener noreferrer"&gt;https://github.com/hashicorp/consul-k8s/issues/1594&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;I hope this is useful in exposure to &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt; service mesh and can help you get started should you want to try this out. If you have services that only listen on a single port, then this certainly an interesting solution to explore.&lt;/p&gt;

&lt;p&gt;If however, you have an application service that needs support for 2+ ports, because you know, &lt;a href="https://kubernetes.io/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; supports this, I would recommend avoiding &lt;a href="https://developer.hashicorp.com/consul/docs/connect" rel="noopener noreferrer"&gt;Consul Connect&lt;/a&gt;, as it is not functional to meet minimum requirements for a service mesh. Perhaps someday, when &lt;a href="https://www.hashicorp.com/" rel="noopener noreferrer"&gt;Hashicorp&lt;/a&gt; prioritizes basic functionality and usability in future version, this product can be considered.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>googlecloud</category>
      <category>consul</category>
      <category>dgraph</category>
    </item>
  </channel>
</rss>
