<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3333361346099343040</id><updated>2025-11-12T08:25:56.911-08:00</updated><category term="java"/><category term="programming"/><category term="kubernetes"/><category term="clinical_trials"/><category term="software"/><category term="ajdt"/><category term="aop"/><category term="aspectj"/><category term="aspects"/><category term="gitops"/><category term="log"/><category term="quality"/><category term="analytics"/><category term="containers"/><category term="devops"/><category term="trace"/><category term="aact"/><category term="cloud"/><category term="jazzsm"/><category term="oncology"/><category term="serviceability"/><category term="ant"/><category term="argocd"/><category term="availability"/><category term="cicd"/><category term="cloudfoundry"/><category term="container-probes"/><category term="ddtunit"/><category term="eclipse"/><category term="jsr47"/><category term="log4j"/><category term="modernization"/><category term="oslc"/><category term="performance"/><category term="probes"/><category term="rdf"/><category term="registry"/><category term="registry-services"/><category term="test"/><category term="xml"/><category term="agile"/><category term="aiops"/><category term="aiops-series"/><category term="analysis"/><category term="automation"/><category term="autoscaling"/><category term="aws"/><category term="bluemix"/><category term="cognos"/><category term="dashboard"/><category term="db2"/><category term="design"/><category term="dns"/><category term="framework"/><category term="genomics"/><category term="javascript"/><category term="jazz"/><category term="junit"/><category term="k8s"/><category term="logging"/><category term="mlops"/><category term="nct"/><category term="observability"/><category term="operations"/><category term="paas"/><category term="saas"/><category term="staf"/><category term="stax"/><category term="tips"/><category term="unit-test"/><category term="unit-testing"/><category term="visualization"/><category term="xslt"/><category term="aad"/><category term="abdera"/><category term="advocate"/><category term="ai"/><category term="animation"/><category term="ant-xslt"/><category term="antcall"/><category term="apache"/><category term="appsody"/><category term="argo"/><category term="atom"/><category term="auto-boxing"/><category term="azure"/><category term="backup"/><category term="birt"/><category term="blogging"/><category term="bookmarks"/><category term="burndown"/><category term="burnup"/><category term="cancer"/><category term="capacity"/><category term="career"/><category term="certificate"/><category term="classloader"/><category term="classpath"/><category term="clone"/><category term="cloudoe"/><category term="code"/><category term="command"/><category term="contextual"/><category term="cost"/><category term="css"/><category term="dashboarding"/><category term="data-driven-unit-test"/><category term="date"/><category term="deeplearning"/><category term="development"/><category term="dict"/><category term="docker"/><category term="docker-desktop"/><category term="dojo"/><category term="dojo-1.2"/><category term="dojo.anim"/><category term="embedded"/><category term="expiration"/><category term="export"/><category term="feed"/><category term="filter"/><category term="flux"/><category term="format"/><category term="gcp"/><category term="geolocation"/><category term="gephi"/><category term="github"/><category term="google"/><category term="helm"/><category term="hive"/><category term="howto"/><category term="hpa"/><category term="html"/><category term="ibm-communities"/><category term="iptables"/><category term="jav"/><category term="jena"/><category term="jmock"/><category term="jmockit"/><category term="jquery"/><category term="keystore"/><category term="knative"/><category term="kustomize"/><category term="lambda"/><category term="lotus-connections"/><category term="lyo"/><category term="menu"/><category term="microservices"/><category term="msct"/><category term="multi-cloud"/><category term="nlp"/><category term="noops"/><category term="numbers"/><category term="on-call"/><category term="openshift"/><category term="openwhisk"/><category term="oslc4j"/><category term="override"/><category term="paginated"/><category term="parser"/><category term="password"/><category term="polygonal"/><category term="pr"/><category term="pretty"/><category term="process"/><category term="productivity"/><category term="project"/><category term="project-management"/><category term="properties"/><category term="python"/><category term="query"/><category term="rate-limiting"/><category term="rational"/><category term="rd"/><category term="rdbms"/><category term="rdf-query"/><category term="re"/><category term="report"/><category term="rtc"/><category term="sample"/><category term="scrum"/><category term="secrets"/><category term="security"/><category term="serverless"/><category term="splash-screen"/><category term="static"/><category term="statistics"/><category term="target"/><category term="tensorflow"/><category term="terraform"/><category term="timestamp"/><category term="tls"/><category term="type-overflow"/><category term="ubuntu"/><category term="ui"/><category term="vault"/><category term="vpa"/><category term="warehouse"/><category term="was"/><category term="watson"/><category term="watson_analytics"/><category term="windows"/><category term="windows-10 azure-active-directory"/><category term="windows-live-writer"/><category term="wink"/><category term="xml-format"/><category term="xmlbeans"/><title type='text'>Source Patch</title><subtitle type='html'>My coding and development scratch pad, from programming to design techniques.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>66</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-2756151184221972968</id><published>2022-12-06T08:39:00.007-08:00</published><updated>2022-12-06T10:28:10.872-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="hive"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="openshift"/><category scheme="http://www.blogger.com/atom/ns#" term="tls"/><title type='text'>Using Let’s Encrypt certificates on managed clusters with OpenShift Hive</title><content type='html'>&lt;p&gt;
  &amp;nbsp;&lt;i style=&quot;color: #24292f;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;(You can see the source code behind this article in this&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/tree/main/hive-trusted-api-endpoint&quot; target=&quot;_blank&quot;&gt;GitHub repository&lt;/a&gt;)&amp;nbsp;&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;ul style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#using-lets-encrypt-certificates-on-managed-clusters-with-openshift-hive&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Using Let’s Encrypt certificates on managed clusters with OpenShift
      Hive&lt;/a&gt;
    &lt;ul style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; padding-left: 2em;&quot;&gt;
      &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#overview&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Overview&lt;/a&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#signed-api-endpoint-certificates&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Signed API endpoint certificates&lt;/a&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#signing-the-api-endpoint&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Signing the API endpoint&lt;/a&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#updating-hives-configuration&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Updating Hive’s configuration&lt;/a&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#conclusion&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Conclusion&lt;/a&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;overview&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Overview&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#overview&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  &lt;a href=&quot;https://github.com/openshift/hive/&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;OpenShift Hive&lt;/a&gt;&amp;nbsp;is a Kubernetes cluster management platform for provisioning and
  configuring Kubernetes clusters at scale.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  As a management platform, it can create new OpenShift clusters across all
  major Cloud providers and perform limited management operations on clusters it
  creates, such as hibernating clusters that are temporarily not in use.
&lt;/p&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Diagram with OpenShift Hive on the left and three OpenShift managed clusters on the right. The OpenShift Hive cluster has an outgoing arrow connecting to each cluster on the right, and the arrow is labeled &amp;quot;Kubernetes API.&amp;quot;&quot; src=&quot;https://nastacio.github.io/blogs/hive-trusted-api-endpoint/images/hive-ocp-api.svg&quot; style=&quot;border-style: none; box-sizing: content-box; margin-left: auto; margin-right: auto; max-width: 100%;&quot; title=&quot;OpenShift Hive creates and manages Kubernetes clusters.&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;OpenShift Hive creates and manages Kubernetes clusters.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; text-align: center;&quot;&gt;
  
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Note:&lt;/span&gt;&amp;nbsp;I use
  OpenShift Hive through&amp;nbsp;&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_advanced_cluster_management_for_kubernetes/2.6&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Red Hat Advanced Cluster Management for Kubernetes&lt;/a&gt;. I tried to generalize the writing and instructions so that they work when
  running OpenShift Hive in isolation, but have not validated the instructions
  using that environment.
&lt;/p&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;signed-api-endpoint-certificates&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Signed API endpoint certificates&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#signed-api-endpoint-certificates&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  In a production environment, cluster clients need to trust that they are
  connecting to the actual API endpoint for the cluster and not to a system
  impersonating the cluster.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The straightforward way of enforcing that requirement is to sign the OpenShift
  API endpoint with a certificate authority that clients equally trust.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The challenge for using trusted certificates on managed clusters is two-fold:
&lt;/p&gt;
&lt;ol style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    Currently, OpenShift Hive does not expose APIs to sign (or apply signed)
    certificates for managed clusters
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    OpenShift Hibe is also a client to the managed clusters it creates, as it
    continuously interacts with the clusters to assess their health and perform
    management functions (such as the hibernation task mentioned earlier.)
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Once you sign the API endpoint for the managed cluster, OpenShift Hive reports
  internal errors about not trusting that cluster’s API endpoint, preventing it
  from managing the cluster.
&lt;/p&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Diagram with OpenShift Hive on the left and three OpenShift managed clusters on the right. The OpenShift Hive cluster has an outgoing arrow connecting to each cluster on the right, and the arrow is labeled &amp;quot;Kubernetes API.&amp;quot; The last cluster has the symbol of a key next to it, and the arrow connecting the OpenShift Hive cluster to that cluster has question marks next to it.&quot; src=&quot;https://nastacio.github.io/blogs/hive-trusted-api-endpoint/images/hive-ocp-api-signed.svg&quot; style=&quot;border-style: none; box-sizing: content-box; margin-left: auto; margin-right: auto; max-width: 100%;&quot; title=&quot;OpenShift Hive cannot initially trust certificates added to existing managed clusters.&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;OpenShift Hive cannot initially trust certificates added to existing managed clusters.&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; text-align: center;&quot;&gt;
  
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The solution (credit to&amp;nbsp;&lt;a href=&quot;https://github.com/abutcher&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Andrew Butcher&lt;/a&gt;) is to inform OpenShift Hive about the signing authority for the managed
  cluster, which can take place in two different ways:
&lt;/p&gt;
&lt;ol style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    If the signing authority is shared across all (or many clusters,) modify the
    CA (certificate authority) database for all clusters in the Hive
    configuration.
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Modify the CA database for the individual managed cluster.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  This article explores that second approach since there is no guarantee that a
  single&amp;nbsp;&lt;a href=&quot;https://letsencrypt.org/&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Let’s Encrypt&lt;/a&gt;&amp;nbsp;intermediary signer is the same across multiple clusters. If you want
  to explore that configuration for other purposes (for example, if your
  organization owns the signing certificate,) then you must use the&amp;nbsp;&lt;a href=&quot;https://github.com/openshift/hive/blob/master/hack/set-additional-ca.sh&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;set-additional-ca.sh&lt;/code&gt;&amp;nbsp;script&lt;/a&gt;&amp;nbsp;to&amp;nbsp;&lt;em style=&quot;box-sizing: border-box;&quot;&gt;replace&lt;/em&gt;&amp;nbsp;the
  current CA database (if any) with a new one.
&lt;/p&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;signing-the-api-endpoint&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Signing the API endpoint&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#signing-the-api-endpoint&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The first step is to acquire the certificate using one of the various&amp;nbsp;&lt;a href=&quot;https://letsencrypt.org/docs/client-options/&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;ACME clients&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  For this article, I have a self-managed OpenShift cluster created in an AWS
  account so that we can use the ACME shell script client.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The following snippet assumes you have the&amp;nbsp;&lt;a href=&quot;https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;AWS CLI credentials in place&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Note&lt;/span&gt;: The
  examples use Shell scripting and rely on the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;:?&lt;/code&gt;&amp;nbsp;construct often to ensure that variables next to that symbol are
  actually defined. For example,&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;echo ${a:?}&lt;/code&gt;&amp;nbsp;fails if the variable named&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;a&lt;/code&gt;&amp;nbsp;is not defined or empty.
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# Assuming AWS CLI logged in with an id authorized to interact &lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# with AWS&#39;s Route 53 service&lt;/span&gt;

&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_domain&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# type the name of the cluster domain here, such as mycluster.mylabdomain.com&lt;/span&gt;

&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_api&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;$(&lt;/span&gt;oc get Infrastructure cluster &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;jsonpath&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&#39;{.status.apiServerURL}&#39;&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# These two lines remove the preceding &quot;https://&quot; and &lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# the &quot;:port_nnumber&quot; suffix from the URL&lt;/span&gt;
&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_api&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_api&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;//*&lt;/span&gt;:&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;\/\//&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_api&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_api&lt;/span&gt;&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;//\&lt;/span&gt;:&lt;span class=&quot;p&quot; style=&quot;box-sizing: border-box;&quot;&gt;*/&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;/tmp/certificates
&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

git clone https://github.com/acmesh-official/acme.sh.git &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-b&lt;/span&gt; 3.0.0 &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--depth&lt;/span&gt; 1
&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;cd &lt;/span&gt;acme.sh

&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# Note that the technique below was chosen for the simplicity of the example&lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# since the purpose of this tutorial is to explain how to interact &lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# with the resulting cluster. It connects directly to AWS Route 53 &lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# with the provided credentials, so you should study the CLI &lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# documentation for more secure alternatives.&lt;/span&gt;
./acme.sh &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--issue&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;*.apps.&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_domain&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;api.&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_domain&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--server&lt;/span&gt; letsencrypt &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--dns&lt;/span&gt; dns_aws &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--force&lt;/span&gt;

./acme.sh &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--install-cert&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;*.apps.&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_domain&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;api.&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_domain&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--cert-file&lt;/span&gt; &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;/cert.pem &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--key-file&lt;/span&gt; &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;/key.pem &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--fullchain-file&lt;/span&gt; &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;/fullchain.pem &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--ca-file&lt;/span&gt; &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;/ca.cer
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  At this point, we have the following files:
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; border-spacing: 0px; color: #24292e; display: block; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; overflow: auto; width: 980px;&quot;&gt;
  &lt;thead style=&quot;box-sizing: border-box;&quot;&gt;
    &lt;tr style=&quot;border-top: 1px solid rgb(198, 203, 209); box-sizing: border-box;&quot;&gt;
      &lt;th style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        Certificate
      &lt;/th&gt;
      &lt;th style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        File
      &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody style=&quot;box-sizing: border-box;&quot;&gt;
    &lt;tr style=&quot;border-top: 1px solid rgb(198, 203, 209); box-sizing: border-box;&quot;&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        Server certificate
      &lt;/td&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        ${cert_dir}/cert.pem
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style=&quot;background-color: #f6f8fa; border-top: 1px solid rgb(198, 203, 209); box-sizing: border-box;&quot;&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        Key for the server certificate
      &lt;/td&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        ${cert_dir}/key.pem
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style=&quot;border-top: 1px solid rgb(198, 203, 209); box-sizing: border-box;&quot;&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        Full chain for the certificate authority
      &lt;/td&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        ${cert_dir}/fullchain.pem
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr style=&quot;background-color: #f6f8fa; border-top: 1px solid rgb(198, 203, 209); box-sizing: border-box;&quot;&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        Signing certificate for the server certificate&lt;br /&gt;(this is the most
        important file in the subsequent sections))
      &lt;/td&gt;
      &lt;td style=&quot;border: 1px solid rgb(223, 226, 229); box-sizing: border-box; padding: 6px 13px;&quot;&gt;
        ${cert_dir}/ca.cer
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Now execute the&amp;nbsp;&lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/security/certificates/api-server.html&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;OpenShift instructions to apply the new certificate to the managed
    cluster&lt;/a&gt;. You should be logged in as a cluster administrator in the managed cluster.
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# https://docs.openshift.com/container-platform/4.11/security/certificates/api-server.html&lt;/span&gt;

oc delete secret api-certs &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--ignore-not-found&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-n&lt;/span&gt; openshift-config

oc create secret tls api-certs &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--cert&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;/fullchain.pem&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--key&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;/key.pem&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-n&lt;/span&gt; openshift-config

oc patch apiserver cluster &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--type&lt;/span&gt; merge &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--patch&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;{&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;: {&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;servingCerts&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;: {&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;namedCertificates&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;: [ { &lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;: [  &lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cluster_api&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;  ], &lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;servingCertificate&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;: {&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;api-certs&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt; }}]}}}&quot;&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The cluster may take several minutes to reconfigure internal resources before
  all master nodes respond with the new certificate.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  You can wait for the complete availability of the API endpoints with the
  following command:
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;oc &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;wait &lt;/span&gt;ClusterOperator kube-apiserver &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--for&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;Progressing&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;False &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--timeout&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;1200s
oc &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;wait &lt;/span&gt;ClusterOperator kube-apiserver &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--for&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;Available&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;True &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--timeout&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;1200s
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  At this point, Hive will likely start complaining about the new API
  certificate. You can confirm that by running the following command against the
  cluster running Hive:
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# Assumes you are logged in to the cluster running Hive as an &lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# administrator&lt;/span&gt;

&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;#type the managed cluster name here&lt;/span&gt;

oc describe ClusterDeployment &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--namespace&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The output can be somewhat verbose, but you may see the following fragment
  somewhere in that output:
&lt;/p&gt;
&lt;pre style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 16px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px;&quot;&gt;&lt;code class=&quot;language-txt&quot; style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;    ...
    Last Probe Time:          ...
    Last Transition Time:     ...
    Message:                  Get &quot;https://api.mycluster.mylab.com:6443/api?timeout=32s&quot;: x509: certificate signed by unknown authority
    Reason:                   ErrorConnectingToCluster
    Status:                   True
    Type:                     Unreachable
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;updating-hives-configuration&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Updating Hive’s configuration&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#updating-hives-configuration&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  With the certificate signer in hand, it is time to update Hive’s configuration
  for that cluster.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Conceptually, we want to locate the&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;kubeconfig&lt;/a&gt;&amp;nbsp;file for the managed cluster and update the list of trusted certificate
  authorities with the signing certificate from the previous section.
&lt;/p&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;img alt=&quot;Box representing the cluster running OpenShift Hive. The cluster contains another box representing the namespace corresponding to the cluster (labeled &amp;quot;cluster-a&amp;quot;). Inside the namespace are two resources: the ClusterDeployment resource for cluster A and the &amp;quot;kubeconfig&amp;quot; secret referenced in that ClusterDeployment resource. An arrow connects an icon outside the cluster box, representing the addition of the new signing certificate to the CA database stored in the secret.&quot; height=&quot;640&quot; src=&quot;https://nastacio.github.io/blogs/hive-trusted-api-endpoint/images/hive-ocp-certs.svg&quot; style=&quot;border-style: none; box-sizing: content-box; margin-left: auto; margin-right: auto; max-width: 100%;&quot; title=&quot;OpenShift Hive cannot initially trust certificates added to existing managed clusters.&quot; width=&quot;640&quot; /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;OpenShift Hive cannot initially trust certificates added to existing managed clusters.&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; text-align: center;&quot;&gt;
  
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The first step is to identify the Kubernetes secret containing the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubeconfig&lt;/code&gt;&amp;nbsp;file using the following commands:
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;#type the managed cluster name here&lt;/span&gt;

oc get ClusterDeployment &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--namespace&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;secret_name&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;$(&lt;/span&gt;oc get ClusterDeployment &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--namespace&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;jsonpath&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&#39;{.spec.clusterMetadata.adminKubeconfigSecretRef.name}&#39;&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;secret_name&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  With the secret name in hand, it is time to dump the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubeconfig&lt;/code&gt;&amp;nbsp;contents into a local file so we can modify it and then update it. One
  could edit the downloaded content for this section with a text editor, but you
  can use the scripted approach described below.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Note that since the file contents use the YAML format, the snippet below
  relies on the&amp;nbsp;&lt;a href=&quot;https://mikefarah.gitbook.io/yq/&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;yq&lt;/a&gt;&amp;nbsp;utility:
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;/tmp/hive-ca
&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_yaml&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;-kubeconfig.yaml&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_crt&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;.crt&quot;&lt;/span&gt;

oc extract secret/&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;secret_name&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--namespace&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--keys&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;kubeconfig &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--to&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;- &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_yaml&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

yq &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-r&lt;/span&gt; .clusters[].cluster.certificate-authority-data &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_yaml&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    | &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_crt&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# Shows original CA certs for the managed cluster API server&lt;/span&gt;
&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_crt&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  At this point, the original API certificates are stored in the file designated
  by the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;ca_crt&lt;/code&gt;&amp;nbsp;variable.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The next step is to generate a new CA file with the recent signing
  certificate. Note that one could argue in favor of outright replacing the
  contents of the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubeconfig&lt;/code&gt;&amp;nbsp;CA data, but since there is no documentation about their contents, it
  is safer to combine the contents rather than risk finding out some of the
  contents were helpful for other reasons.
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# This is the CA file for the signing certificate for the cluster-a&lt;/span&gt;
&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;additional_ca_file&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;cert_dir&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;/ca.cer

&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# Merges the existing CA with the new CA&lt;/span&gt;
&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_new_crt_bundle&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;-new.crt&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_crt&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;additional_ca_file&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    | openssl &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-A&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_new_crt_bundle&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# Generates a new kubeconfig file&lt;/span&gt;
&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_new_crt&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_new_crt_bundle&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;)&lt;/span&gt;

yq &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;del (.clusters[0].cluster.certificate-authority-data)&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_yaml&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;

yq &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;.clusters[0].cluster.certificate-authority-data = &lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;ca_new_crt&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_yaml&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  After the previous block, we have an updated version of&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubeconfig&lt;/code&gt;&amp;nbsp;for the cluster stored in the file location designated by
  the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubeconfig_yaml&lt;/code&gt;&amp;nbsp;variable, containing the new signing certificate. The next step is to
  update the original&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;Secret&lt;/code&gt;&amp;nbsp;resource with that new configuration.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Note that there are&amp;nbsp;&lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;2&lt;/span&gt;&amp;nbsp;fields in the secret requiring updates:
&lt;/p&gt;
&lt;ol style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    &lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubeconfig&lt;/code&gt;
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    &lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;raw-kubeconfig&lt;/code&gt;
  &lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_64_yaml&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;-kubeconfig-64.yaml&quot;&lt;/span&gt;
openssl &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-A&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-in&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_yaml&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_64_yaml&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_64&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_64_yaml&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;)&lt;/span&gt;

oc patch Secret &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;secret_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--namespace&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
      &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--type&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&#39;json&#39;&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;-p&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;[{&#39;op&#39;: &#39;replace&#39;, &#39;path&#39;: &#39;/data/kubeconfig&#39;, &#39;value&#39;: &#39;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_64&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&#39;},{&#39;op&#39;: &#39;replace&#39;, &#39;path&#39;: &#39;/data/raw-kubeconfig&#39;, &#39;value&#39;: &#39;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;kubeconfig_64&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&#39;}]&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# It is a good idea to wait for the ClusterDeployment resource&lt;/span&gt;
&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# to report being ready before proceeding&lt;/span&gt;
oc &lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;wait &lt;/span&gt;ClusterDeployment &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--namespace&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--for&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;Ready&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot; style=&quot;box-sizing: border-box; color: #0086b3;&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--timeout&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;600s 
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Assuming everything was executed successfully, OpenShift Hive should now
  recognize the new certificate for the managed cluster.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  You can validate that Hive can connect to the cluster again by running the
  same&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;oc describe&lt;/code&gt;&amp;nbsp;command from earlier:
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;oc describe ClusterDeployment &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--namespace&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;managed_cluster_name&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The command output should contain the following excerpt arount the `Unreachable` condition:
&lt;/p&gt;
&lt;pre style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 16px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px;&quot;&gt;&lt;code class=&quot;language-txt&quot; style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;    ...
    Last Probe Time:          ...
    Last Transition Time:     ...
    Message:                  cluster is reachable
    Reason:                   ClusterReachable
    Status:                   False
    Type:                     Unreachable
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;conclusion&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Conclusion&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#conclusion&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  OpenShift Hive does a great job creating new clusters in supported Cloud
  providers. Still, it currently lacks primitives for certain management
  operations, such as adding a signed certificate to the API endpoints of the
  managed clusters.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  This article shows how to locate and update the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubeconfig&lt;/code&gt;&amp;nbsp;for the managed cluster, using a concrete example and code samples to
  effect the change.
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/2756151184221972968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2756151184221972968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2756151184221972968'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/12/using-lets-encrypt-certificates-on.html' title='Using Let’s Encrypt certificates on managed clusters with OpenShift Hive'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-4946965757922260374</id><published>2022-11-29T14:06:00.013-08:00</published><updated>2022-12-06T08:32:21.604-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aws"/><category scheme="http://www.blogger.com/atom/ns#" term="dns"/><category scheme="http://www.blogger.com/atom/ns#" term="gcp"/><category scheme="http://www.blogger.com/atom/ns#" term="multi-cloud"/><title type='text'>Multi-cloud DNS delegation between GCP and AWS</title><content type='html'>&lt;p&gt;
  &lt;i style=&quot;color: #24292f;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;(You can see the source code behind this article in this&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/tree/main/gcp-dns-aws-route53&quot; target=&quot;_blank&quot;&gt;GitHub repository&lt;/a&gt;)&amp;nbsp;&lt;/span&gt;&lt;/i&gt;
&lt;/p&gt;
&lt;ul style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#multi-cloud-dns-delegation-between-gcp-and-aws&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Multi-cloud DNS delegation between GCP and AWS&lt;/a&gt;
    &lt;ul style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; padding-left: 2em;&quot;&gt;
      &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#overview&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Overview&lt;/a&gt;
        &lt;ul style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; padding-left: 2em;&quot;&gt;
          &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
            &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#dns-record-types&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;DNS record types&lt;/a&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-the-dns-zone-in-gcp&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Create the DNS Zone in GCP&lt;/a&gt;
        &lt;ul style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; padding-left: 2em;&quot;&gt;
          &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
            &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#set-aside-the-list-of-gcp-dns-servers&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Set aside the list of GCP DNS servers&lt;/a&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-delegation-records-in-route-53&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Create delegation records in Route 53&lt;/a&gt;
        &lt;ul style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px; padding-left: 2em;&quot;&gt;
          &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
            &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-name-server-record&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Create Name Server record&lt;/a&gt;
          &lt;/li&gt;
          &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
            &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#optional-restrict-cas-that-can-create-certificates-for-the-domain&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;optional Restrict CAs that can create certificates for the
              domain&lt;/a&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#validating-dns-configuration&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Validating DNS configuration&lt;/a&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-the-openshift-cluster&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Create the OpenShift cluster&lt;/a&gt;
      &lt;/li&gt;
      &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
        &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#conclusion&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Conclusion&lt;/a&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;overview&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Overview&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#overview&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 1; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The use case is hosting services in one cloud provider while having the DNS
  domain for those services managed on a different cloud provider.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  This technique is useful when you group system resources in a hybrid
  multi-cloud environment under the same DNS domain.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  For the example in this article, we already have a DNS domain hosted
  using&amp;nbsp;&lt;a href=&quot;https://aws.amazon.com/route53/&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;AWS DNS (Route 53)&lt;/a&gt;&amp;nbsp;on AWS, and needed to place a set of&amp;nbsp;&lt;a href=&quot;https://www.redhat.com/en/technologies/cloud-computing/openshift/container-platform&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;OpenShift Container Platform (OCP)&lt;/a&gt;&amp;nbsp;clusters in GCP while using a sub-domain of that original DNS domain.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  This diagram illustrates the desired outcome on both DNS zones, with AWS Route
  53 handling the initial requests for names in the primary domain and deferring
  the queries for the sub-domain to the DNS resolvers in GCP.
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgMrpBA7rCbTXz3mp1TgZokyZT--grWm8CLf53X3U6oge0Weir7ysFOSnW9kw1BkjzvOVat3Nns3d4qyc2tcUsqHsfGGPFxLnLvdLBdiTT6u6NyroBRFD-leNXHouH_nzYjtqX7P5yOTkf1o48p__wo6NqCZ2dmtg4Y9b0L1H9vdnswYcw_SRPRrSmoJA&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Component diagram with AWS DNS on the right and GCP DNS on the right. AWS DNS box has NS and SOA records for the DNS domain and an NS record for the sub-domain in GCP. GCP DNS box has NS and SOA records for the DNS sub-domain and NS records for the OpenShift cluster endpoints.&quot; data-original-height=&quot;465&quot; data-original-width=&quot;781&quot; height=&quot;382&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgMrpBA7rCbTXz3mp1TgZokyZT--grWm8CLf53X3U6oge0Weir7ysFOSnW9kw1BkjzvOVat3Nns3d4qyc2tcUsqHsfGGPFxLnLvdLBdiTT6u6NyroBRFD-leNXHouH_nzYjtqX7P5yOTkf1o48p__wo6NqCZ2dmtg4Y9b0L1H9vdnswYcw_SRPRrSmoJA=w640-h382&quot; title=&quot;Component diagram of the solution in this article.&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Component diagram of the solution in this article.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  There are two underlying assumptions for this type of solution:
&lt;/p&gt;
&lt;ol style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    The cluster administrator has considered the implications of making the DNS
    names of the new cluster publicly available. Note that this is unrelated to
    whether the cluster endpoints are accessible publicly.
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    The cluster administrator is responsible for ensuring clients have a proper
    network path to the network hosting the endpoints. For instance, if the new
    OCP cluster is created on a private subnet, clients outside that subnet may
    be able to resolve the DNS name for the cluster’s console or API server.
    Still, they will not be able to establish a network connection to those
    endpoints.
  &lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;dns-record-types&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
  DNS record types&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#dns-record-types&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h3&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  It may be helpful, although not strictly necessary, to understand a bit more
  about&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_DNS_record_types&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;DNS record types&lt;/a&gt;&amp;nbsp;as you follow along this tutorial.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  For this tutorial, these are the most relevant record types:
&lt;/p&gt;
&lt;blockquote style=&quot;border-left: 0.25em solid rgb(223, 226, 229); box-sizing: border-box; color: #6a737d; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin: 0px 0px 16px; padding: 0px 1em; text-align: left;&quot;&gt;
  &lt;ul style=&quot;text-align: left;&quot;&gt;
    &lt;li&gt;
      &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;NS&lt;/span&gt;:
      Delegates a DNS zone to use the given authoritative name servers.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;A&lt;/span&gt;: Returns a
      32-bit IPv4 address, most commonly used to map hostnames to an IP address
      of the host, but it is also used for DNSBLs, storing subnet masks in RFC
      1101, etc.
    &lt;/li&gt;
    &lt;li&gt;
      &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;SOA&lt;/span&gt;:
      Specifies authoritative information about a DNS zone, including the
      primary name server, the email of the domain administrator, the domain
      serial number, and several timers relating to refreshing the zone.
    &lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;create-the-dns-zone-in-gcp&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Create the DNS Zone in GCP&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-the-dns-zone-in-gcp&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The first step is to create a non-authoritative&amp;nbsp;&lt;a href=&quot;https://cloud.google.com/dns/docs/overview&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;DNS Zone in GCP&lt;/a&gt;, using a sub-domain of the hosted domain in Route 53.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The hosted domain in Route 53 is “cloudpak-bringup.com,” whereas the
  sub-domain will be “gcp.cloudpak-bringup.com”
&lt;/p&gt;
&lt;ul style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;Click on the “Create Zone” button.&lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Use&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;cloud-pak-bring up-lab&lt;/code&gt;&amp;nbsp;as the zone name.
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Use&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;gcp.cloudpak-bringup.com&lt;/code&gt;&amp;nbsp;as the DNS name.
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Click the “Create” button.
  &lt;/li&gt;&lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;&lt;br /&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/gcp-cloudpak-dns-zone-create-1.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Screenshot of &amp;quot;Cloud DNS zone&amp;quot; in the &amp;quot;Network services&amp;quot; panel of the GCP console.&quot; border=&quot;0&quot; data-original-height=&quot;764&quot; data-original-width=&quot;800&quot; height=&quot;611&quot; src=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/gcp-cloudpak-dns-zone-create-1.png&quot; title=&quot;Creation form for the DNS zone&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-family: Times;&quot;&gt;&lt;br /&gt;Creation form for the DNS zone&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;
        
      &lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The following listing shows the alternative command if using the GCP CLI:
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;project_id&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;c&quot; style=&quot;box-sizing: border-box; color: #999988; font-style: italic;&quot;&gt;# type your GCP project id here&lt;/span&gt;
gcloud dns &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    managed-zones create cloud-pak-bringup-lab &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--project&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot; style=&quot;box-sizing: border-box; color: teal;&quot;&gt;project_id&lt;/span&gt;:?&lt;span class=&quot;k&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--description&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;Test clusters tied to the Bringup Lab activities.&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--dns-name&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;gcp.cloudpak-bringup.com.&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--visibility&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;public&quot;&lt;/span&gt; &lt;span class=&quot;se&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;nt&quot; style=&quot;box-sizing: border-box; color: navy;&quot;&gt;--dnssec-state&lt;/span&gt;&lt;span class=&quot;o&quot; style=&quot;box-sizing: border-box; color: black; font-weight: bold;&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot; style=&quot;box-sizing: border-box; color: #dd1144;&quot;&gt;&quot;off&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Once the DNS zone is created, you should see the following screen:
&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/gcp-cloudpak-dns-zone.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;![View of the &amp;quot;Resource record set details&amp;quot; containing the list of DNS names for the new DNS zone&quot; border=&quot;0&quot; data-original-height=&quot;408&quot; data-original-width=&quot;800&quot; height=&quot;327&quot; src=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/gcp-cloudpak-dns-zone.png&quot; title=&quot;List of DNS names for the new DNS zone&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;DNS Zone in GCP Console&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;set-aside-the-list-of-gcp-dns-servers&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;Set aside the list of GCP DNS servers&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#set-aside-the-list-of-gcp-dns-servers&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h3&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Click on the “NS” entry named “gcp.cloudpak-bringup.com” to see the resource
  record set details.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Write down the list of name servers under the “Routing data” table. That list
  is needed later when configuring the DNS zone in AWS.
&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/gcp-cloudpak-dns-zone-routing-data.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;View of the &amp;quot;Resource record set details&amp;quot; containing the list of DNS names for the new DNS zone&quot; border=&quot;0&quot; data-original-height=&quot;465&quot; data-original-width=&quot;800&quot; height=&quot;372&quot; src=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/gcp-cloudpak-dns-zone-routing-data.png&quot; title=&quot;List of DNS names for the new DNS zone&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;List of DNS names for the new DNS zone&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;The list contains the following records in our example, but your DNS record
  may have a different list of DNS servers.
&lt;/p&gt;
&lt;pre style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 16px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px;&quot;&gt;&lt;code class=&quot;language-txt&quot; style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;ns-cloud-e1.googledomains.com.
ns-cloud-e2.googledomains.com.
ns-cloud-e3.googledomains.com.
ns-cloud-e4.googledomains.com.
&lt;/code&gt;&lt;/pre&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;create-delegation-records-in-route-53&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Create delegation records in Route 53&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-delegation-records-in-route-53&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Locate the hosted zone in the&amp;nbsp;&lt;a href=&quot;https://console.aws.amazon.com/route53&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Route 53 page of the AWS Console&lt;/a&gt;.
&lt;/p&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/aws-route-53-dns-zone.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Screenshot of the &amp;quot;Hosted zone&amp;quot; in the &amp;quot;Route 53&amp;quot; panel of the AWS console&quot; border=&quot;0&quot; data-original-height=&quot;376&quot; data-original-width=&quot;800&quot; height=&quot;301&quot; src=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/aws-route-53-dns-zone.png&quot; title=&quot;Authoritative DNS Zone in AWS&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;Authoritative DNS Zone in AWS&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3 id=&quot;create-name-server-record&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;Create Name Server record&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-name-server-record&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h3&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The name server record informs AWS Route 53 to delegate all requests for a
  sub-domain of the hosted zone to a list of name servers.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  In our case, we want to associate the “gcp.cloudpak-bringup.com” sub-domain
  with the list of name servers obtained from the DNS zone created earlier in
  GCP.
&lt;/p&gt;
&lt;ul style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    Click on “Create Record” and choose the “Simple routing” strategy if
    prompted for the routing strategy.
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Type&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;gcp&lt;/code&gt;&amp;nbsp;as the record name
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Select “NS - Name servers for a hosted zone” as the “Record Type.” Note that
    this option is grayed out until you fill out the “Record name” field.
  &lt;/li&gt;
  &lt;li class=&quot;code-line&quot; data-line=&quot;113&quot; dir=&quot;auto&quot; style=&quot;position: relative;&quot;&gt;
    Under &quot;Value,&quot; paste the list of DNS name servers from the GCP DNS zone.
  &lt;/li&gt;
  &lt;li class=&quot;code-line&quot; data-line=&quot;114&quot; dir=&quot;auto&quot; style=&quot;position: relative;&quot;&gt;
    Click the &quot;Create records&quot; button.
  &lt;/li&gt;
&lt;/ul&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/aws-route-53-dns-zone-ns.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Screenshot of the creation panel for the NS record in the &amp;quot;Route 53&amp;quot; portion of the AWS console&quot; border=&quot;0&quot; data-original-height=&quot;569&quot; data-original-width=&quot;800&quot; height=&quot;455&quot; src=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/aws-route-53-dns-zone-ns.png&quot; title=&quot;Creation of the delegated NS record for the DNS sub-domain in AWS&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;Creation of the delegated NS record for the DNS sub-domain in AWS&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;h3 id=&quot;optional-restrict-cas-that-can-create-certificates-for-the-domain&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h3 id=&quot;optional-restrict-cas-that-can-create-certificates-for-the-domain&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
  (optional) Restrict CAs that can create certificates for the domain&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#optional-restrict-cas-that-can-create-certificates-for-the-domain&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h3&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Create an additional record to indicate which CA’s can create certificates for
  the sub-domain.
&lt;/p&gt;
&lt;ul style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    Click on “Create Record” and choose the “Simple routing” strategy if
    prompted for the routing strategy.
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Use&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;gcp&lt;/code&gt;&amp;nbsp;as the “Record name” field, matching the sub-domain used when
    creating the DNS zone in GCP.
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Pick “CAA – Restricts CAs that can create SSL/TLS certificates for the
    domain” as the “Record Type.”
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Choose the appropriate issuer value for the CA authority. For example, for
    “Let’s Encrypt,” use&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;0 issue &quot;letsencrypt.org&quot;&lt;/code&gt;
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    Keep the other default values.
  &lt;/li&gt;
  &lt;li class=&quot;code-line&quot; data-line=&quot;113&quot; dir=&quot;auto&quot; style=&quot;position: relative;&quot;&gt;
    Click the &quot;Create records&quot; button.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/aws-route-53-dns-zone-caa.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Screenshot of the creation panel for the CAA record in the &amp;quot;Route 53&amp;quot; portion of the AWS console&quot; border=&quot;0&quot; data-original-height=&quot;562&quot; data-original-width=&quot;800&quot; height=&quot;450&quot; src=&quot;https://raw.githubusercontent.com/nastacio/blogs/main/gcp-dns-aws-route53/images/aws-route-53-dns-zone-caa.png&quot; title=&quot;Creation of the CAA record for the DNS sub-domain in AWS&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Creation of the CAA record for the DNS sub-domain in AWS&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2 id=&quot;validating-dns-configuration&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;Validating DNS configuration&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#validating-dns-configuration&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Once the DNS records are configured in both cloud providers, it is a good idea
  to validate the setup before attempting to create the OpenShift cluster (or
  whatever other service you want to respond to in the new sub-domain.)
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Note that some DNS settings typically take a few moments to propagate across
  the various DNS servers on the Internet.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  This example command queries the authority for a pseudo hostname in the new
  sub-domain:
&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot; style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px;&quot;&gt;
  &lt;div class=&quot;highlight&quot; style=&quot;background-color: #f8f8f8; box-sizing: border-box; margin-bottom: 16px;&quot;&gt;
    &lt;pre class=&quot;highlight&quot; style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;code style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;dig some-non-existent-service.gcp.cloudpak-bringup.com soa +noall +authority
&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The command results should indicate that GCP is the authority for the
  sub-domain, like in the following snippet:
&lt;/p&gt;
&lt;pre style=&quot;background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; color: #24292e; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 16px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px;&quot;&gt;&lt;code class=&quot;language-txt&quot; style=&quot;background: transparent; border-radius: 3px; border: 0px; box-sizing: border-box; display: inline; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; line-height: inherit; margin: 0px; overflow-wrap: normal; overflow: visible; padding: 0px; word-break: normal;&quot;&gt;
; &amp;lt;&amp;lt;&amp;gt;&amp;gt; DiG 9.10.6 &amp;lt;&amp;lt;&amp;gt;&amp;gt; some-non-existent-service.gcp.cloudpak-bringup.com 
soa +noall +authority
;; global options: +cmd
gcp.cloudpak-bringup.com. 300 IN  SOA ns-cloud-e1.googledomains.com. 
cloud-dns-hostmaster.google.com. 1 21600 3600 259200 300
&lt;/code&gt;&lt;/pre&gt;
&lt;hr style=&quot;background: rgb(225, 228, 232); border: 0px; box-sizing: content-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;
&lt;h2 id=&quot;create-the-openshift-cluster&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Create the OpenShift cluster&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#create-the-openshift-cluster&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  With the DNS resolution configured in both clouds, it is time to create the
  OpenShift cluster in GCP.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  There are multiple methods for creating an OpenShift cluster on GCP Cloud. The
  most basic methods are listed in the&amp;nbsp;&lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/installing/installing_gcp/preparing-to-install-on-gcp.html&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;OpenShift Container Platform documentation&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  There are more sophisticated mechanisms, such as&amp;nbsp;&lt;a href=&quot;https://access.redhat.com/documentation/en-us/red_hat_advanced_cluster_management_for_kubernetes/&quot; style=&quot;background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;&quot;&gt;Red Hat Advanced Cluster Management for Kubernetes&lt;/a&gt;.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Whatever method you choose, use the new sub-domain as the&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;baseDomain&lt;/code&gt;&amp;nbsp;field:&amp;nbsp;&lt;code class=&quot;language-plaintext highlighter-rouge&quot; style=&quot;background-color: rgba(27, 31, 35, 0.05); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, Courier, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;gcp.cloudpak-bringup.com&lt;/code&gt;.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  Once the cluster creation completes, you should see two new “A” type DNS
  records for the OCP endpoints in the GCP console:
&lt;/p&gt;
&lt;ul style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
    *.apps.clustername.cloudpak-bringup.com
  &lt;/li&gt;
  &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
    api.clustername.cloudpak-bringup.com
  &lt;/li&gt;&lt;/ul&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEi0KoTSsyYjBeDexCYKFdfFGUkkXTNNlU5d_GSzsjHFu_CohHRVOPYEjh9Gmt79ACB_ofGEAE3YcgtzR8EcCtlkrHrf66BRJDgKOkcpjAhEhspeFpVabhaUSnPTDmK5wZzQ8qcZvirEexe9fU2l1C3164f_OP4PsihzIi7Nw--__HNDzKm9GNnz4Ny8VQ&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Screenshot of DNS record sets in the new DNS zone created in GCP&quot; data-original-height=&quot;1274&quot; data-original-width=&quot;2442&quot; height=&quot;334&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEi0KoTSsyYjBeDexCYKFdfFGUkkXTNNlU5d_GSzsjHFu_CohHRVOPYEjh9Gmt79ACB_ofGEAE3YcgtzR8EcCtlkrHrf66BRJDgKOkcpjAhEhspeFpVabhaUSnPTDmK5wZzQ8qcZvirEexe9fU2l1C3164f_OP4PsihzIi7Nw--__HNDzKm9GNnz4Ny8VQ=w640-h334&quot; title=&quot;OCP cluster routes for the new cluster&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;OCP cluster routes for the new cluster&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
&lt;/ul&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;With those DNS records in place, you can now access the resulting cluster
  endpoints using their DNS names and not resort to local alterations.
&lt;/p&gt;&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;/p&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEj9-wnLFsOiycXtWNyWRGN6lTtxms2y9ab5MiKBwAaxxT00PmAvihr1SojGGu0WzOI7S8WAtQLHdhRyfwo95cE9E8GxNt7zvRCTxjp_Rl-ke63HWIuXbMX3RZ2TKQmDdKPjPAQWOmUmetWcpqFm8lngmt3ETD2G79g-FZt-xRwTQb2eG06TzEGfbR3d7Q&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Screenshot of web browser showing the host name of the OpenShift Container Platform console hosted in the new DNS sub-domain&quot; data-original-height=&quot;1512&quot; data-original-width=&quot;1652&quot; height=&quot;586&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEj9-wnLFsOiycXtWNyWRGN6lTtxms2y9ab5MiKBwAaxxT00PmAvihr1SojGGu0WzOI7S8WAtQLHdhRyfwo95cE9E8GxNt7zvRCTxjp_Rl-ke63HWIuXbMX3RZ2TKQmDdKPjPAQWOmUmetWcpqFm8lngmt3ETD2G79g-FZt-xRwTQb2eG06TzEGfbR3d7Q=w640-h586&quot; title=&quot;OCP console hosted in the new DNS sub-domain&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;OCP console hosted in the new DNS sub-domain&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot; style=&quot;border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
  Conclusion&lt;a aria-label=&quot;Anchor&quot; class=&quot;anchorjs-link&quot; data-anchorjs-icon=&quot;&quot; href=&quot;https://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#conclusion&quot; style=&quot;-webkit-font-smoothing: antialiased; background-color: transparent; box-sizing: border-box; color: #0366d6; font-family: anchorjs-icons; font-size: 1em; font-stretch: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: normal; line-height: 1; opacity: 0; padding-left: 0.375em; text-decoration-line: none;&quot;&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  This type of DNS delegation is a common solution for hybrid multi-cloud
  arrangements where you want to share the primary DNS domain name for all
  systems spread across the different clouds.
&lt;/p&gt;
&lt;p style=&quot;box-sizing: border-box; color: #24292e; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
  The detailed instructions should be sufficient to generalize the solution to
  different DNS providers, paying attention to the placement of the appropriate
  “NS” DNS records in the respective DNS zones.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/4946965757922260374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/4946965757922260374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/4946965757922260374'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/11/multi-cloud-dns-delegation-between-gcp.html' title='Multi-cloud DNS delegation between GCP and AWS'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgMrpBA7rCbTXz3mp1TgZokyZT--grWm8CLf53X3U6oge0Weir7ysFOSnW9kw1BkjzvOVat3Nns3d4qyc2tcUsqHsfGGPFxLnLvdLBdiTT6u6NyroBRFD-leNXHouH_nzYjtqX7P5yOTkf1o48p__wo6NqCZ2dmtg4Y9b0L1H9vdnswYcw_SRPRrSmoJA=s72-w640-h382-c" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Raleigh, NC, USA</georss:featurename><georss:point>35.7795897 -78.6381787</georss:point><georss:box>7.469355863821157 -113.7944287 64.089823536178841 -43.4819287</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-6755856382382560509</id><published>2022-10-19T06:00:00.017-07:00</published><updated>2023-10-10T04:27:26.934-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="autoscaling"/><category scheme="http://www.blogger.com/atom/ns#" term="knative"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="microservices"/><title type='text'>Running Knative services on AWS spot instances</title><content type='html'>&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;&quot; style=&quot;background-color: white; color: #24292f; font-weight: 400;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;
  &lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;&quot; style=&quot;background-color: white; color: #24292f; font-weight: 400;&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;(You can see the source code behind this article in this
        &lt;a href=&quot;https://github.com/nastacio/blogs/tree/main/knative-interruptible&quot; target=&quot;_blank&quot;&gt;GitHub repository&lt;/a&gt;)&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;background-color: white; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px;&quot;&gt;&lt;br /&gt;This article is a technical exploration of several technologies to reduce
    the cost of running workloads in Kubernetes.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The exploration goes into how the characteristics of each of these
    technologies favor certain types of workloads and ultimately combines all
    these components into a deployment strategy that utilizes their core
    strengths.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The general approach works better with containers designed using serverless
    principles, such as reduced internal state, lightweight footprints, and
    quick startup times.
  &lt;/p&gt;
  &lt;br /&gt;&lt;/div&gt;&lt;span&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;
  &lt;h2 dir=&quot;auto&quot; style=&quot;background-color: white; border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-components&quot; id=&quot;user-content-components&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Components
  &lt;/h2&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    This section lists the core components of this article, a brief overview,
    and pointers for further reading.
  &lt;/p&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;a href=&quot;#user-content-openshift-container-platform&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift Container Platform&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-aws-and-spot-instances&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;AWS and Spot Instances&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-knative&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Knative&lt;/a&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;a href=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/knative-spot-autoscale.png&quot; rel=&quot;noopener noreferrer&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;Box representing OpenShift cluster, containing boxes representing two types of machine sets. One machine set has multiple machines with triple dollar signs and a callout for &amp;quot;traditional workloads.&amp;quot; The other machine set is captioned &amp;quot;interruptible,&amp;quot; has a single dollar sign, and is captioned &amp;quot;knative workloads&amp;quot;&quot; src=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/knative-spot-autoscale.png&quot; style=&quot;background-color: var(--color-canvas-default); border-style: none; box-sizing: content-box; max-width: 100%;&quot; title=&quot;OpenShift cluster with two types of machine sets for two distinct types of workloads.&quot; /&gt;&lt;/a&gt;
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Note&lt;/span&gt;: I
    struggled with the decision to use OpenShift over&amp;nbsp;&lt;a href=&quot;https://aws.amazon.com/eks/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;EKS&lt;/a&gt;&amp;nbsp;for this tutorial. On the one hand, using AWS as the cloud provider
    makes EKS a more natural choice. On the other hand, I have easy access to
    OpenShift licenses, which also makes the article more readily portable to GCP and
    Azure. If you prefer using an EKS cluster, replace the OpenShift portions
    with the instructions in this&amp;nbsp;&lt;a href=&quot;https://aws.amazon.com/getting-started/hands-on/amazon-eks-with-spot-instances/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;AWS tutorial&lt;/a&gt;, where &quot;Spot Managed node groups&quot; are the rough functional equivalent to
    the concept of OpenShift machine sets.
  &lt;/p&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-openshift-container-platform&quot; id=&quot;user-content-openshift-container-platform&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;OpenShift Container Platform
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    OpenShift Container Platform (OCP) is a Kubernetes distribution from Red
    Hat.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    OCP adds a rich management interface around the Kubernetes runtime, making
    it easier to install the open-source components used in this article and,
    most importantly, visualize the resources and browse their metrics. I made a
    special effort to avoid using OCP-specific commands where possible, making
    life a little easier for those who wish to attempt this exercise with a
    different distribution or even &quot;plain&quot; Kubernetes.
  &lt;/p&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-aws-and-spot-instances&quot; id=&quot;user-content-aws-and-spot-instances&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;AWS and Spot Instances
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    I chose AWS as the cloud provider in this experiment for a few reasons:
  &lt;/p&gt;
  &lt;ol dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      It supports the concept of &quot;spot instances,&quot; where customers can request
      instances from a pool of spare capacity in the provider. These instances
      are relatively cheaper than regular instances, with one catch: the cloud
      provider can take them back after giving your cluster a short notice
      (typically 30 to 60 seconds).
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      OpenShift has native support for requesting spot instances from AWS.
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      It is the most widely used public cloud provider, making this examination
      relevant to a broader audience.
    &lt;/li&gt;
  &lt;/ol&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Note that OpenShift also has native support for allocating nodes on Azure or
    Google Cloud spot instances, so you should be able to replicate the same
    setup with minor changes to the OCP MachineSet samples in this article.
  &lt;/p&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-knative&quot; id=&quot;user-content-knative&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Knative
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Knative is my favorite auto-scaling component in Kubernetes, not the least
    because it favors a stateless micro-service pattern that carries very into the various serverless offerings across different cloud
    providers.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    At its core, Knative has the&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;&quot;Serving&quot;&lt;/a&gt;&amp;nbsp;component, which processes&amp;nbsp;&lt;a href=&quot;https://github.com/knative/specs/raw/main/specs/serving/knative-api-specification-1.0.md#service&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Knative service definitions&lt;/a&gt;. Service definitions map to various&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/knative-kubernetes-services/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Kubernetes services&lt;/a&gt;, combining a container image with targets of&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/autoscaling/concurrency/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;concurrency&lt;/a&gt;&amp;nbsp;and sustained&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/autoscaling/rps-target/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;requests per second&lt;/a&gt;.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The serving component manages the number of replicas for that container to
    meet service targets. Depending on the service definition, terminates all
    containers for that workload when there are no more incoming requests.
  &lt;/p&gt;
  &lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;!--more--&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
  &lt;h2 dir=&quot;auto&quot; style=&quot;background-color: white; border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-environment-configuration&quot; id=&quot;user-content-environment-configuration&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Environment configuration
  &lt;/h2&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;a href=&quot;#user-content-choose-the-aws-region-for-the-cluster&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Choose the AWS region for the cluster&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-create-an-ocp-411-cluster&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Create an OCP 4.11 cluster&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-create-the-ocp-machineset-using-spot-instances&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Create the OCP MachineSet using spot instances&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-create-cluster-and-machine-autoscalers&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Create cluster and machine autoscalers&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-install-knative-on-the-cluster&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Install Knative on the cluster&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-enable-knative-feature-flags&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Enable Knative feature flags&lt;/a&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Note&lt;/span&gt;: This
    section requires you to apply many resources mentioned in the article to the
    cluster. You can apply them from a terminal using &lt;a href=&quot;https://linuxize.com/post/bash-heredoc/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Heredoc constructs&lt;/a&gt;&amp;nbsp;(see below) or using the OpenShift&amp;nbsp;&lt;a href=&quot;http://openshift.github.io/openshift-origin-design/designs/administrator/future-openshift/import-yaml/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Import YAML&lt;/a&gt;&amp;nbsp;button.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;#&lt;/span&gt; make sure you logged into the cluster &lt;/span&gt;
&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;#&lt;/span&gt; from this terminal session&lt;/span&gt;

cat &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;EOF&lt;/span&gt; | kubectl apply -f -&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;...yaml resource copy-pasted from the article&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;EOF&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-choose-the-aws-region-for-the-cluster&quot; id=&quot;user-content-choose-the-aws-region-for-the-cluster&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Choose the AWS region for the cluster
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Assuming you have the flexibility to choose the AWS region, try and choose
    one with a higher &quot;placement score&quot; of provisioning spot instances.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can assess that score using the &quot;Spot placement score&quot; page of the AWS
    console and play with different requirements for the number of instances,
    CPUs, and memory size.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The inline documentation on the page is pretty self-explanatory about the
    odds of acquiring spot instances meeting your requirements.
  &lt;/p&gt;
  &lt;blockquote style=&quot;background-color: white; border-left: 0.25em solid var(--color-border-default); box-sizing: border-box; color: var(--color-fg-muted); font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin: 0px 0px 16px; padding: 0px 1em;&quot;&gt;
    &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px;&quot;&gt;
      Scores serve as a guideline, and no score guarantees that your Spot
      request will be fully or partially fulfilled. A score of 10 means that
      your Spot capacity request is highly likely to succeed in that Region or
      Availability Zone at the time of the request. A score of 1 means that your
      Spot capacity request is not likely to succeed.
    &lt;/p&gt;
  &lt;/blockquote&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    I experimented with many size combinations, and the placement scores matched
    my expectation that smaller instances (e.g., 4x16) would have higher scores
    than larger instances (e.g., 16x64.)
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    My empirical results also showed that the placement score was a good
    indicator of how soon the cloud provider would reclaim the spot instance.
    Requesting spot instances of size 16x64 was essentially unusable for a
    Kubernetes cluster, with the cluster spending more time bringing an instance
    online than actually being able to load pods in the instance. The results
    may vary with region and time of day, but statistically speaking, working
    with smaller spot instances tends to yield much better results.
  &lt;/p&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-create-an-ocp-411-cluster&quot; id=&quot;user-content-create-an-ocp-411-cluster&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create an OCP 4.11 cluster
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Note&lt;/span&gt;: I
    mentioned earlier that it is possible to replace OCP with an AWS EKS cluster
    - using &quot;Spot Managed node groups&quot; instead of OCP machine sets. If there is
    enough interest, I can try and replicate the entire exercise with EKS.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    These instructions were tested with OCP 4.11.7 but should work on OCP 4.6
    and above.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    I recommend that you use&amp;nbsp;&lt;em style=&quot;box-sizing: border-box;&quot;&gt;at least three availability zones&lt;/em&gt;&amp;nbsp;in the target region (e.g., pick&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;us-east-1a&lt;/code&gt;,&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;us-east-1b&lt;/code&gt;, and&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;us-east-1c&lt;/code&gt;&amp;nbsp;availability zones if installing the cluster in the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;us-east-1&lt;/code&gt;&amp;nbsp;region.) The multiple availability zones help later in the setup when
    it is time to create the new worker pool using spot instances.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can install OCP on AWS using different variations of the IPI procedure
    (Installer Provisioned Infrastructure,) where the installer requests all
    infrastructure components from the cloud provider and loads the Kubernetes
    software on the resulting computing instances.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The&amp;nbsp;&lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/installing/index.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OCP&#39;s installation documentation&lt;/a&gt;&amp;nbsp;covers the entire procedure, so instead of repeating those
    instructions, I will add a few comments about the variations:
  &lt;/p&gt;
  &lt;ol dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        Use Red Hat&#39;s cloud console. This method also offers a user interface
        around the IPI-based installation, creating a cluster that is
        functionally equivalent to the other methods.
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        Using Red Hat Advanced Cluster Management for Kubernetes. Assuming you
        have access to this product, it offers a user interface around the
        IPI-based installation process, which you can use to create the cluster
        with a few clicks without getting distracted collecting keys and
        certificates for the installation process.
      &lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-create-the-ocp-machineset-using-spot-instances&quot; id=&quot;user-content-create-the-ocp-machineset-using-spot-instances&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create the OCP MachineSet using spot instances
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/machine_management/index.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OCP machine sets&lt;/a&gt;&amp;nbsp;abstract the underlying cloud provider compute instances for the
    cluster nodes.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    A machine set contains the cloud provider-specific information required to
    provision new compute instances, such as the region, availability zone,
    number of CPUs, amount of memory, disk capacity, subnets, and a few others.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/images/ocp-machine-set.png&quot; rel=&quot;noopener noreferrer&quot; style=&quot;box-sizing: border-box;&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;Box representing OpenShift cluster, containing boxes representing two types of machine sets. One machine set has multiple machines with triple dollar signs and a callout for &amp;quot;traditional workloads.&amp;quot; The other machine set is captioned &amp;quot;interruptible,&amp;quot; has a single dollar sign, and is captioned &amp;quot;knative workloads&amp;quot;&quot; height=&quot;433&quot; src=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/ocp-machine-set.png&quot; style=&quot;background-color: var(--color-canvas-default); border-style: none; box-sizing: content-box; max-width: 100%;&quot; title=&quot;OCP machine sets, availability zones, and Kubernetes nodes.&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    OCP requests that &quot;machine&quot; to the cloud provider, and once the resulting
    cloud instance is ready, OCP loads it with all the software required to run
    a Kubernetes node and makes it a part of the cluster.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    For illustrative purposes, the following listing is the example of a
    MachineSet resource immediately after requesting the creation of an OCP
    cluster. I stripped out a few Kubernetes elements to make it a little more
    readable, but you can see the entire resource&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/ocp-machine-set-original.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;here&lt;/a&gt;.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-yaml notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;machine.openshift.io/v1beta1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;MachineSet&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;cluster-name-worker-us-east-1a&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;namespace&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;openshift-machine-api&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;replicas&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;template&lt;/span&gt;:
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;labels&lt;/span&gt;:
        &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;{}&lt;/span&gt;
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;providerSpec&lt;/span&gt;:
        &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;value&lt;/span&gt;:
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;machine.openshift.io/v1beta1&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;AWSMachineProviderConfig&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;instanceType&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;m5.xlarge&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;blockDevices&lt;/span&gt;:
            - &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;ebs&lt;/span&gt;:
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;placement&lt;/span&gt;:
            &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;availabilityZone&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;us-east-1a&lt;/span&gt;
            &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;region&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;us-east-1&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;securityGroups&lt;/span&gt;:
            &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;...&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;subnet&lt;/span&gt;:
            &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;...&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Creating a new machine set requires applying a custom resource to the
    cluster, like the one in the previous section. Ultimately, the machine set
    for using AWS spot instances is not that different from a regular machine
    set, although it requires a few essential modifications:
  &lt;/p&gt;
  &lt;ol dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      Adding a&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;spotMarketOptions&lt;/code&gt;&amp;nbsp;element to the node template. A node template is an element in the
      machine set that tells OCP about the extra configuration of the cluster
      node associated with each instance. The&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;spotMarketOptions&lt;/code&gt;&amp;nbsp;element informs OCP that it should request AWS for spot instances
      instead of on-demand instances. A related feature not explored in the
      article is the ability to include a&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;maxPrice&lt;/code&gt;&amp;nbsp;inside the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;spotMarketOptions&lt;/code&gt;&amp;nbsp;element, indicating the maximum hourly rate you are willing to pay
      for the instance, which can be pretty helpful in specific scenarios.
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Adding a taint to the node template so that only workloads with toleration
      for that taint will run in the node. This setting prevents essential pods
      or pods that cannot tolerate frequent interruptions from landing in the
      nodes created on EC2 spot instances.
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Adding a label to the nodes indicating that they run on interruptible
      instances. Later we can tell Knative to provision service pods with an
      affinity for those nodes.
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      (optional) Add a label indicating the purpose of these machines (and
      respective cluster nodes.) This label is helpful when it is time to delete
      the machine set.
    &lt;/li&gt;
  &lt;/ol&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The definition of specific fields can be quite involved, such as secrets and
    subnets, so I tend to copy and then modify one of the existing machine sets
    in the cluster. I wrote&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/scripts/create-machine-set.sh&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;an example using shell script and the yq utility&lt;/a&gt;&amp;nbsp;to create the machine sets to request spot instances.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;#!&lt;/span&gt;/bin/sh&lt;/span&gt;

infra_id=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;$(&lt;/span&gt;kubectl get Infrastructure cluster -o jsonpath=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;{.status.infrastructureName}&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;Infrastructure id is: &lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${infra_id}&lt;/span&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;#&lt;/span&gt; Make sure to pick a valid instance type for the cloud region&lt;/span&gt;
instance_size=&lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${1&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:-&lt;/span&gt;c5a.xlarge}&lt;/span&gt;

kubectl get MachineSet \
        -n openshift-machine-api \
        --selector hive.openshift.io/machine-pool=worker \
        --selector hive.openshift.io/managed=true \
        -o yaml \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].status)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].metadata.annotations)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].metadata.uid)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].metadata.resourceVersion)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].metadata.generation)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].metadata.creationTimestamp)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].metadata.labels.&quot;hive.openshift.io/managed&quot;)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;del (.items[].metadata.labels.&quot;hive.openshift.io/machine-pool&quot;)&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;.items[].metadata.labels += { &quot;machine.sourcepatch.com/interruptible&quot;: &quot;true&quot; }&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;.items[].spec.template.metadata.labels += { &quot;machine.sourcepatch.com/interruptible&quot;: &quot;true&quot; }&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;.items[].spec.template.spec.providerSpec.value.spotMarketOptions={}&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;.items[].spec.template.spec.taints += [{ &quot;effect&quot;: &quot;NoSchedule&quot;, &quot;key&quot;: &quot;workload.sourcepatch.com/interruptible&quot;, &quot;value&quot;: &quot;true&quot; }]&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;.items[].spec.template.spec.metadata.labels += { &quot;sourcepatch.com/node.interruptible&quot;: &quot;true&quot;}&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; yq &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;.items[].spec.template.spec.providerSpec.value.instanceType= &lt;span class=&quot;pl-cce&quot; style=&quot;box-sizing: border-box;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${instance_size&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:?&lt;/span&gt;}&lt;/span&gt;&lt;span class=&quot;pl-cce&quot; style=&quot;box-sizing: border-box;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; sed &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;s/name: &lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${infra_id&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:?&lt;/span&gt;}&lt;/span&gt;-worker/name: &lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${infra_id&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:?&lt;/span&gt;}&lt;/span&gt;-worker-spot/&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; sed &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;s/machineset: &lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${infra_id&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:?&lt;/span&gt;}&lt;/span&gt;-worker/machineset: &lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${infra_id&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:?&lt;/span&gt;}&lt;/span&gt;-worker-spot/&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; kubectl apply -f -&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can see a graphical visualization of the differences between an&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/ocp-machine-set-original.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;original machine set&lt;/a&gt;&amp;nbsp;and an&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/ocp-machine-set-interruptible.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;interruptible machine set&lt;/a&gt;&amp;nbsp;in the illustration below.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;a href=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/machineset-diff-original-vs-spot.png&quot; rel=&quot;noopener noreferrer&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;Side-by-side differences between a standard machine set and the same machine set modified to allocate spot instances. There are roughly 70 lines of code in the modified machine set, with a few lines adding a node label and a node taint to the node template.&quot; src=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/machineset-diff-original-vs-spot.png&quot; style=&quot;background-color: var(--color-canvas-default); border-style: none; box-sizing: content-box; max-width: 100%;&quot; title=&quot;Differences between the original machine set and the one modified for running spot instances&quot; /&gt;&lt;/a&gt;
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Immediately after creating the new machine sets, you may notice that they
    may not report as ready or available. You can use the following command to
    list their status, noticing how it selects the results using the label added
    in the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;.spec.template.metadata.labels&lt;/code&gt;&amp;nbsp;section of the&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/ocp-machine-set-interruptible.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;modified machine set&lt;/a&gt;.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl get machineset \
    -n openshift-machine-api \
    --selector machine.sourcepatch.com/interruptible=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The command should produce an output like this:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;NAME                         DESIRED   CURRENT   READY   AVAILABLE   AGE
...-worker-spot-us-east-1a   1         1                             6s
...-worker-spot-us-east-1b   1         1                             6s
...-worker-spot-us-east-1c   1         1                             6s
...-worker-spot-us-east-1d   1         1                             6s&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    After a couple of minutes, assuming the cloud provider fulfilled the spot
    instance requests, you should see the machines (OCP&#39;s representation of the
    cloud provider instances) already running with the requested instance type.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Repeat the previous command until it produces an output like this:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;NAME                         DESIRED   CURRENT   READY   AVAILABLE   AGE
...-worker-spot-us-east-1a   1         1         1       1           5m1s
...-worker-spot-us-east-1b   1         1         1       1           5m1s
...-worker-spot-us-east-1c   1         1         1       1           5m1s
...-worker-spot-us-east-1d   1         1         1       1           5m1s&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    After another couple of minutes, with all required software loaded into the
    instances, you should also see the Kubernetes nodes added to the cluster.
    You can verify the state of the new nodes with the command below, noticing
    how it targets the nodes using the node label declared in the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;.spec.template.spec.metadata.labels&lt;/code&gt;&amp;nbsp;section of the&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/ocp-machine-set-interruptible.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;modified machine set&lt;/a&gt;.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl get node \
    --selector sourcepatch.com/node.interruptible=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The command should produce an output similar to this:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;NAME                           STATUS   ROLES    AGE     VERSION
ip-10-0-nnn-200.ec2.internal   Ready    worker   6m42s   v1.24.0+...
ip-10-0-nnn-201.ec2.internal   Ready    worker   7m11s   v1.24.0+...
ip-10-0-nnn-202.ec2.internal   Ready    worker   6m31s   v1.24.0+...
ip-10-0-nnn-203.ec2.internal   Ready    worker   6m24s   v1.24.0+...&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You should also be able to see the EC2 spot instances allocated in the
    respective AWS panel. Those instance requests have a status of &quot;fulfilled.&quot;
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;a href=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/aws-spot-instance-allocated.png&quot; rel=&quot;noopener noreferrer&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;AWS panel for &amp;quot;Spot requests,&amp;quot; showing a table of requests, with a line per instance. The bottom lines are older and indicate instances that have already been returned to the provider. Lines at the top show records with the status of &amp;quot;Fulfilled&amp;quot; and their respective age.&quot; src=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/aws-spot-instance-allocated.png&quot; style=&quot;background-color: var(--color-canvas-default); border-style: none; box-sizing: content-box; max-width: 100%;&quot; title=&quot;AWS Spot requests panel&quot; /&gt;&lt;/a&gt;
  &lt;/p&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-create-cluster-and-machine-autoscalers&quot; id=&quot;user-content-create-cluster-and-machine-autoscalers&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create cluster and machine autoscalers
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    As an optional feature, OCP machine sets can have a variable range of
    machines instead of a fixed number of replicas. OCP uses pod scheduling
    information in the cluster to decide the optimal number of instances in a
    machine set.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The first step to leverage that feature is to enable the&amp;nbsp;&lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/machine_management/applying-autoscaling.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OCP cluster autoscaler feature&lt;/a&gt;, applying the following resource to the cluster (you can also find this
    resource in the&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/cluster-autoscaler.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;GitHub repository for this article&lt;/a&gt;.)
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Important&lt;/span&gt;: The
    settings in this&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;ClusterAutoscaler&lt;/code&gt;&amp;nbsp;resource are adequate for the relatively small examples in the
    article. Make sure you read the OCP documentation for detailed information
    and important considerations for each setting.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-yaml notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;---
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;autoscaling.openshift.io/v1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;ClusterAutoscaler&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;default&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;podPriorityThreshold&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;-10&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;resourceLimits&lt;/span&gt;:
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;maxNodesTotal&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;24&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;cores&lt;/span&gt;:
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;min&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;8&lt;/span&gt;
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;max&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;128&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;memory&lt;/span&gt;:
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;min&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;4&lt;/span&gt;
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;max&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;256&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;scaleDown&lt;/span&gt;:
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;enabled&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;delayAfterAdd&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;10m&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;delayAfterDelete&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;5m&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;delayAfterFailure&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;30s&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;unneededTime&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;5m&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;utilizationThreshold&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;0.4&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The second step is to create&amp;nbsp;&lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/machine_management/applying-autoscaling.html#machine-autoscaler-about_applying-autoscaling&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OCP machine autoscalers&lt;/a&gt;&amp;nbsp;for the machine sets created in the previous sections. You need one
    machine autoscaler per machine set, which tells OCP to adjust the number of
    replicas in the respective machine set to match the capacity requirements of
    the cluster.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can create the resources using a&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/scripts/create-machine-autoscalers.sh&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;code block like the one below&lt;/a&gt;, which iterates through the names of the machine sets created in the
    previous section. It establishes the respective autoscaler for the machine
    set, with a range of 0 to 3 machines:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl get MachineSet \
    -n openshift-machine-api \
    --selector machine.sourcepatch.com/interruptible=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; \
    -o template=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;{{range .items}}{{.metadata.name}}{{&quot;\n&quot;}}{{end}}&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt; \
&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;read&lt;/span&gt; -r ms
&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;do&lt;/span&gt;
  cat &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;EOF&lt;/span&gt; | kubectl apply -f -&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion: autoscaling.openshift.io/v1beta1&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind: MachineAutoscaler&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata:&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;  labels:&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;    machine.sourcepatch.com/interruptible: &quot;true&quot;&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;  name: &lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${ms}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;  namespace: openshift-machine-api&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec:&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;  minReplicas: 0&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;  maxReplicas: 3&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;  scaleTargetRef:&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;    apiVersion: machine.openshift.io/v1beta1&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;    kind: MachineSet&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;    name: &lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${ms}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;EOF&lt;/span&gt;
&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;done&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Since the minimum number of replicas was set to zero, and given the taint in
    the interruptible machine sets preventing other workloads from running in
    those nodes, the cluster should eventually delete all machines associated
    with the new machine sets until there are pods scheduled to run on those
    nodes.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can observe the node deletion progress by listing the machine resources
    labeled with the label assigned to their respective machine set in the
    previous sections.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl get Machine \
    -n openshift-machine-api \
    --selector machine.sourcepatch.com/interruptible=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    If you timed it right, you should see an output like the one below, where
    you can still see the cluster deleting the unused nodes.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;NAME                            PHASE     TYPE       REGION    ZONE       AGE
...-worker-spot-us-east-1b-...  Deleting  c5a.xlarge us-east-1 us-east-1b 13m
...-worker-spot-us-east-1c-...  Running   c5a.xlarge us-east-1 us-east-1c 13m
...-worker-spot-us-east-1d-...  Running   c5a.xlarge us-east-1 us-east-1d 13m&lt;/pre&gt;
  &lt;/div&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-install-knative-on-the-cluster&quot; id=&quot;user-content-install-knative-on-the-cluster&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Install Knative on the cluster
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Installing Knative in OCP is simplified through the concept of&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/docs/concepts/extend-kubernetes/operator/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Kubernetes operators&lt;/a&gt;. OCP calls it the&amp;nbsp;&lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/serverless/serverless-release-notes.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Openshift Serverless operator&lt;/a&gt;, which is essentially a downstream version of the Knative open-source
    project.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can install the OpenShift Serverless operator directly from the OCP
    console by navigating to the&amp;nbsp;&lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/operators/understanding/olm-understanding-operatorhub.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OperatorHub&lt;/a&gt;&amp;nbsp;tab, selecting &quot;OpenShift Serverless&quot; and clicking &quot;Install.&quot;
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can also install the operator from a terminal, applying the&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/openshift-serverless.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;respective operator group and subscription resources&lt;/a&gt;, like the one listed below for convenience:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-yaml notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;---
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Namespace&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;openshift-serverless&lt;/span&gt;
---
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;operators.coreos.com/v1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;OperatorGroup&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;openshift-serverless-group&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;namespace&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;openshift-serverless&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;upgradeStrategy&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Default&lt;/span&gt;
---
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;operators.coreos.com/v1alpha1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Subscription&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;serverless-operator&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;namespace&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;openshift-serverless&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;channel&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;stable&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;installPlanApproval&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Automatic&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;serverless-operator&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;source&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;redhat-operators&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;sourceNamespace&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;openshift-marketplace&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The next step is to install the Knative serving instance, which is
    responsible for the scheduling of containers to meet the targets of Knative
    service definitions.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can see this resource in&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/blob/main/knative-interruptible/descriptors/knative-serving.yaml&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;source format&lt;/a&gt;, which is listed for reading convenience here:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-yaml notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;---
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;operator.knative.dev/v1alpha1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;KnativeServing&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;knative-serving&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;namespace&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;knative-serving&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;cluster-local-gateway&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;controller-custom-certs&lt;/span&gt;:
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;knative-ingress-gateway&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;registry&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;{}&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-enable-knative-feature-flags&quot; id=&quot;user-content-enable-knative-feature-flags&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Enable Knative feature flags
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    As of now, and by default, Knative does not enable pod affinity and taint
    tolerations for Knative service definitions. If you attempt to create
    Knative service definitions before enabling those features, you will receive
    error messages like this:
  &lt;/p&gt;
  &lt;blockquote style=&quot;background-color: white; border-left: 0.25em solid var(--color-border-default); box-sizing: border-box; color: var(--color-fg-muted); font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin: 0px 0px 16px; padding: 0px 1em;&quot;&gt;
    &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px;&quot;&gt;
      Error from server (BadRequest): error when creating &quot;STDIN&quot;: admission
      webhook &quot;validation.webhook.serving.knative.dev&quot; denied the request:
      validation failed: must not set the field(s):
      spec.template.spec.nodeSelector, spec.template.spec.tolerations
    &lt;/p&gt;
  &lt;/blockquote&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    and
  &lt;/p&gt;
  &lt;blockquote style=&quot;background-color: white; border-left: 0.25em solid var(--color-border-default); box-sizing: border-box; color: var(--color-fg-muted); font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin: 0px 0px 16px; padding: 0px 1em;&quot;&gt;
    &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 0px; margin-top: 0px;&quot;&gt;
      Error from server (BadRequest): error when creating &quot;STDIN&quot;: admission
      webhook &quot;validation.webhook.serving.knative.dev&quot; denied the request:
      validation failed: must not set the field(s):
      spec.template.spec.tolerations
    &lt;/p&gt;
  &lt;/blockquote&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Before you can use those Knative features, you must enable the
    corresponding&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/configuration/feature-flags/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;feature flags&lt;/a&gt;&amp;nbsp;:
  &lt;/p&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        Pod spec affinity:&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/configuration/feature-flags/#kubernetes-node-affinity&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;https://knative.dev/docs/serving/configuration/feature-flags/#kubernetes-node-affinity&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        Enable taint toleration:&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/configuration/feature-flags/#kubernetes-toleration&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;https://knative.dev/docs/serving/configuration/feature-flags/#kubernetes-toleration&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can modify the Knative configuration object directly from the OpenShift
    console or run these two commands from a terminal:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl patch ConfigMap config-features \
    -n knative-serving \
    -p &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;{&quot;data&quot;:{&quot;kubernetes.podspec-affinity&quot;:&quot;enabled&quot;}}&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;

kubectl patch ConfigMap config-features \
    -n knative-serving \
    -p &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;{&quot;data&quot;:{&quot;kubernetes.podspec-tolerations&quot;:&quot;enabled&quot;}}&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The examples in this article do not use the&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/configuration/feature-flags/#kubernetes-node-selector&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;node selector feature&lt;/a&gt;. Still, you can enable it if you want to experiment with different
    strategies for matching Knative workloads to specific nodes:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl patch ConfigMap config-features \
    -n knative-serving \
    -p &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;{&quot;data&quot;:{&quot;kubernetes.podspec-nodeselector&quot;:&quot;disabled&quot;}}&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&#39;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    And now we can start creating Knative service definitions.
  &lt;/p&gt;
  &lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 0px; box-sizing: content-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; height: 0.25em; margin: 24px 0px; padding: 0px;&quot; /&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h2 dir=&quot;auto&quot; style=&quot;background-color: white; border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;&lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-components&quot; id=&quot;user-content-components&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;&lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/h2&gt;&lt;/div&gt;
  &lt;h2 dir=&quot;auto&quot; style=&quot;background-color: white; border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-service-requests-with-spot-instances&quot; id=&quot;user-content-service-requests-with-spot-instances&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Service requests with spot instances
  &lt;/h2&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    This section shows all components working together. The first step is to
    create the&amp;nbsp;&lt;a href=&quot;https://github.com/knative/specs/raw/main/specs/serving/knative-api-specification-1.0.md#service&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Knative service definition&lt;/a&gt;, which gives us a target service endpoint, then use a utility to exercise
    that endpoint.
  &lt;/p&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;a href=&quot;#user-content-create-service-definitions&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Create service definitions&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-the-service-sample&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;The service sample&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-validating-the-service-readiness&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Validating the service readiness&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-validating-the-installation&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Validating the installation&lt;/a&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;a href=&quot;#user-content-driving-heavy-loads&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Driving heavy loads&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/setup-complete.png&quot; rel=&quot;noopener noreferrer&quot; style=&quot;background-color: white; box-sizing: border-box; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px;&quot; target=&quot;_blank&quot;&gt;&lt;img alt=&quot;Box representing an OpenShift cluster, containing boxes representing three main groups of nodes: master, worker, and the new interruptible nodes. The OpenShift cluster box also includes the Knative component. Knative only pushes pods to the interruptible nodes. In contrast, other pods in the cluster are not scheduled in those interruptible nodes due to not having toleration for the &amp;quot;interruptible&amp;quot; taint.&quot; src=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/setup-complete.png&quot; style=&quot;background-color: var(--color-canvas-default); border-style: none; box-sizing: content-box; max-width: 100%;&quot; title=&quot;Setup with all components installed and interacting with one another.&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
  &lt;/ul&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-create-service-definitions&quot; id=&quot;user-content-create-service-definitions&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Create service definitions
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    A Knative service definition is analogous to pairing a Kubernetes workload
    definition with a Kubernetes service. You can read the entire service
    specification for details, which I summarize as follows:
  &lt;/p&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      Container settings, such as image source, resource requests, limits, probe
      definitions
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Service settings include the service&#39;s endpoint URL, target concurrency,
      and throughput metrics.
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Routing settings, such as how much traffic goes to each service revision.
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The Knative serving module listens to incoming requests on an endpoint and
    continuously decides the ideal number of containers to meet the service
    targets - concurrency and requests per second.
  &lt;/p&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-the-service-sample&quot; id=&quot;user-content-the-service-sample&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;The service sample
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The basis for this section is a heavily modified version of this Knative
    code sample:&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/autoscaling/autoscale-go/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;https://knative.dev/docs/serving/autoscaling/autoscale-go/&lt;/a&gt;.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Create a Knative service instance with an affinity for the nodes created
    from the machine set in the previous sections (identified with the
    &quot;node.interruptible&quot; label) and toleration for the interruptible taint
    (identified with the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;node.interruptible&lt;/code&gt;&amp;nbsp;taint:)
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-yaml notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;---
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Namespace&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;knative-interruptible&lt;/span&gt;
---
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;apiVersion&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;serving.knative.dev/v1&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;kind&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Service&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;mywork&lt;/span&gt;
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;namespace&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;knative-interruptible&lt;/span&gt;
&lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
  &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;template&lt;/span&gt;:
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;metadata&lt;/span&gt;:
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;annotations&lt;/span&gt;:
        &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;autoscaling.knative.dev/target-utilization-percentage&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;70&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;autoscaling.knative.dev/target&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;10&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;spec&lt;/span&gt;:
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;containerConcurrency&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;15&lt;/span&gt;
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;containers&lt;/span&gt;:
        - &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;image&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;gcr.io/knative-samples/autoscale-go:0.1&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;name&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;user-container&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;resources&lt;/span&gt;:
            &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;requests&lt;/span&gt;:
              &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;memory&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;256Mi&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
              &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;cpu&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;200m&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;limits&lt;/span&gt;:
              &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;memory&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;256Mi&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
              &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;cpu&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;200m&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;enableServiceLinks&lt;/span&gt;: &lt;span class=&quot;pl-c1&quot; color=&quot;var(--color-prettylights-syntax-constant)&quot; style=&quot;box-sizing: border-box;&quot;&gt;false&lt;/span&gt;

      &lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;#&lt;/span&gt; Schedule pods in nodes labeled &lt;/span&gt;
      &lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;#&lt;/span&gt; &quot;sourcepatch.com/node.interruptible&quot;&lt;/span&gt;
      &lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-c&quot; color=&quot;var(--color-prettylights-syntax-comment)&quot; style=&quot;box-sizing: border-box;&quot;&gt;#&lt;/span&gt; and tolerate their respective taints.&lt;/span&gt;
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;affinity&lt;/span&gt;:
        &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;nodeAffinity&lt;/span&gt;:
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;requiredDuringSchedulingIgnoredDuringExecution&lt;/span&gt;:
            &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;nodeSelectorTerms&lt;/span&gt;:
              - &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;matchExpressions&lt;/span&gt;:
                  - &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;key&lt;/span&gt;:  &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;sourcepatch.com/node.interruptible&lt;/span&gt;
                    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;operator&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;Exists&lt;/span&gt;
                    &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;values&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;[]&lt;/span&gt;
      &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;tolerations&lt;/span&gt;:
        - &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;key&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;workload.sourcepatch.com/interruptible&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;operator&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;Exists&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
          &lt;span class=&quot;pl-ent&quot; color=&quot;var(--color-prettylights-syntax-entity-tag)&quot; style=&quot;box-sizing: border-box;&quot;&gt;effect&lt;/span&gt;: &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;NoSchedule&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-validating-the-service-readiness&quot; id=&quot;user-content-validating-the-service-readiness&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Validating the service readiness
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Before we start sending the request, let&#39;s first validate that the service
    is ready:
  &lt;/p&gt;
  &lt;ol dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://knative.dev/docs/client/install-kn/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Install the Knative CLI&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        Ask for the service details:
      &lt;/p&gt;
      &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
        &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kn service describe mywork -n knative-interruptible&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    At this point, all interruptible nodes may have been deallocated due to
    inactivity. In that case, you would see the message &quot;Error: Unschedulable`
    for the service revision.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;Name:       mywork
Namespace:  knative-interruptible
Age:        12s
URL:        https://mywork-knative-interruptible.apps.mycluster.domain.io

Revisions:
      &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;!&lt;/span&gt;  mywork-00001 (latest created) [1] (12s)
        Error:  Unschedulable
        Image:  gcr.io/knative-samples/autoscale-go:0.1 (at e5e89c)

Conditions:
  OK TYPE                   AGE REASON
  &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;!!&lt;/span&gt; Ready                  12s RevisionMissing
  &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;!!&lt;/span&gt; ConfigurationsReady    12s RevisionFailed
  &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;!!&lt;/span&gt; RoutesReady            12s RevisionMissing&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can confirm that the problem is only temporary due to the machine
    autoscaler being in the process of allocating a new node by inspecting the
    service&#39;s underlying pods.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl get pods \
    -n knative-interruptible \
    --selector serving.knative.dev/service=mywork -o yaml&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    If you waited too long to run the previous command, you might get an empty
    list result, which is potentially a good sign, indicating that Knative was
    able to create the pod, validate that the service is configured correctly,
    and terminate the pod.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    In that case, your service is configured correctly, and you can skip the
    following paragraphs about troubleshooting potential (or transitory)
    scheduling problems.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    In case the pods are still pending, they should contain output resembling
    something like the output below:
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;{ ... &quot;conditions&quot;: [ { &quot;lastProbeTime&quot;: null, &quot;lastTransitionTime&quot;:
      &quot;2022-10-17T20:02:38Z&quot;, &quot;message&quot;: &quot;0/7 nodes are available: 3 node(s) had
      untolerated taint {node-role.kubernetes.io/master: }, 7 node(s) didn&#39;t
      match Pod&#39;s node affinity/selector. preemption: 0/7 nodes are available: 7
      Preemption is not helpful for scheduling.&quot;, &quot;reason&quot;: &quot;Unschedulable&quot;,
      &quot;status&quot;: &quot;False&quot;, &quot;type&quot;: &quot;PodScheduled&quot; } ], &quot;phase&quot;: &quot;Pending&quot;,
      &quot;qosClass&quot;: &quot;Burstable&quot; }&lt;/code&gt;
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can further confirm that problem is transitory by listing the available
    machines in the machine set created in this article:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kubectl get Machine \
    -n openshift-machine-api \
    --selector machine.sourcepatch.com/interruptible&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The command could produce an output like this, indicating that a machine is
    being provisioned:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;NAME                 PHASE          TYPE         REGION      ZONE         AGE
...-worker-spot...   Provisioning   c5a.xlarge   us-east-1   us-east-1b   24s&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Under these circumstances, the new interruptible node should be ready in a
    couple more minutes, in which case the Knative service should report being
    ready.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You can validate that the service is ready by running the following command:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kn service describe mywork -n knative-interruptible&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    The output should look something like this:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;Name:       mywork
Namespace:  knative-interruptible
Age:        3m
URL:        https://mywork-knative-interruptible.apps.mycluster.domain.io

Revisions:
  100%  @latest (mywork-00001) [1] (3m)
        Image:     gcr.io/knative-samples/autoscale-go:0.1 (at e5e89c)
        Replicas:  1/1

Conditions:
  OK TYPE                   AGE REASON
  ++ Ready                  40s
  ++ ConfigurationsReady    41s
  ++ RoutesReady            40s&lt;/pre&gt;
  &lt;/div&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-validating-the-installation&quot; id=&quot;user-content-validating-the-installation&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Validating the installation
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    There are many alternatives for validating the installation, such as the
    ones in the following list:
  &lt;/p&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        A simple&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;curl&lt;/code&gt;&amp;nbsp;request to the service endpoint
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        If you plan to take this exploration into production, I strongly
        encourage you to look into something like the&amp;nbsp;&lt;a href=&quot;https://k6.io/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;&lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;K6 framework&lt;/span&gt;&lt;/a&gt;, then&amp;nbsp;&lt;a href=&quot;https://medium.com/swlh/beautiful-load-testing-with-k6-and-docker-compose-4454edb3a2e3&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;set up K6 locally&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href=&quot;https://k6.io/blog/running-distributed-tests-on-k8s/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;in the cluster&lt;/a&gt;&amp;nbsp;to gather detailed metrics for continued analysis during
        development and post-deployment.
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        Use the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;hey&lt;/code&gt;&amp;nbsp;load generator (&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;go install github.com/rakyll/hey@latest&lt;/code&gt;)&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/autoscaling/autoscale-go/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;referenced in the Knative documentation&lt;/a&gt;.
      &lt;/p&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Note&lt;/span&gt;: You
        will need to&amp;nbsp;&lt;a href=&quot;https://go.dev/doc/install&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;install the Golang SDK&lt;/a&gt;&amp;nbsp;before installing the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;hey&lt;/code&gt;&amp;nbsp;utility since the project does not release binaries for all
        platforms. The utility, by default, will be downloaded to&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;$HOME/go/bin&lt;/code&gt;, and you can move it to a system folder in our&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;PATH&lt;/code&gt;&amp;nbsp;environment variable such as&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;/usr/bin&lt;/code&gt;&amp;nbsp;or&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;/usr/local/bin&lt;/code&gt;
      &lt;/p&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    &lt;span style=&quot;box-sizing: border-box; font-weight: 600;&quot;&gt;Important&lt;/span&gt;:
    When running a performance load utility such as K6 and&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;hey&lt;/code&gt;, be particularly mindful of&amp;nbsp;&lt;em style=&quot;box-sizing: border-box;&quot;&gt;where&lt;/em&gt;&amp;nbsp;you will run the utility, considering the network bandwidth and data
    transfer costs between the client and the cluster. I strongly suggest you
    run these utilities from a location as close as possible to the cluster,
    such as another compute instance in the same private subnet where the
    cluster nodes are running.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    For this article, I am using the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;hey&lt;/code&gt;&amp;nbsp;utility, which provides a good balance of ease of use with the
    ability to generate controlled bursts of requests toward a service endpoint.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Let&#39;s start with a run of 5 sustained requests over 30 seconds:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;url=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;$(&lt;/span&gt;kn service describe mywork -n knative-interruptible -o url&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

hey -z 10s -c 5 -t 240 &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${url&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:?&lt;/span&gt;}&lt;/span&gt;?sleep=100&amp;amp;prime=10000&amp;amp;bloat=5&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; kubectl get pods -n knative-interruptible&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Note the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;-t 240&lt;/code&gt;&amp;nbsp;parameter, which instructs the utility to wait longer for responses
    from the service, accounting for the possibility that all autoscaled machine
    sets created in this article may have scaled down to zero before you got to
    this step.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    This light load does not require many pods but is a good warm-up exercise,
    and successful responses validate that all components are working correctly.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    While the utility is still querying the service, run the following command
    from a different terminal to determine the service status:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;kn service describe mywork -n knative-interruptible&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Notice that at first, due to the machine set autoscaling configured in
    previous sections, the machine set for these pods may not have any machine
    allocated to them, which may lead to an output like this:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;Name:       mywork
Namespace:  knative-interruptible
Age:        16m
URL:        https://mywork-knative-interruptible.apps.mycluster.domain.io

Revisions:  
  100&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;!&lt;/span&gt;  @latest (mywork-00001) [1] (16m)
        Error:     Unschedulable
        Image:     gcr.io/knative-samples/autoscale-go:0.1 (at e5e89c)
        Replicas:  0/7

Conditions:  
  OK TYPE                   AGE REASON
  &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;!!&lt;/span&gt; Ready                  13s RevisionFailed
  &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;!!&lt;/span&gt; ConfigurationsReady    13s RevisionFailed
  ++ RoutesReady            13m &lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Notice how the field&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;Replicas&lt;/code&gt;&amp;nbsp;lists&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;0/7&lt;/code&gt;, indicating that Knative assessed the need for seven replicas to handle
    the incoming requests and that zero of those pods could be allocated until a
    new node comes online.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    If you wait a few more minutes, repeating the previous command should
    produce an output like this:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;Name:       mywork
Namespace:  knative-interruptible
Age:        3h
URL:        https://mywork-knative-interruptible.apps.mycluster.domain.io

Revisions:
  100%  @latest (mywork-00001) [1] (24m)
        Image:     gcr.io/knative-samples/autoscale-go:0.1 (at e5e89c)
        Replicas:  7/7

Conditions:
  OK TYPE                   AGE REASON
  ++ Ready                  24m
  ++ ConfigurationsReady    24m
  ++ RoutesReady            24m&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    We can see that the service is reporting being ready and has determined that
    it allocated all seven container replicas to meet the service requirements.
  &lt;/p&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-driving-heavy-loads&quot; id=&quot;user-content-driving-heavy-loads&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Driving heavy loads
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    With the installation validated, it is time to generate a higher load to
    exercise the total capacity of the pool of interruptible nodes.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Let&#39;s request sustained 250 requests per second for 300 seconds. Note the
    usage of 300-second timeout (using the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;-t 300&lt;/code&gt;&amp;nbsp;parameter) to account for the time it may take for any eventual
    scaling up of a machine set.
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;url=&lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;$(&lt;/span&gt;kn service describe mywork -n knative-interruptible -o url&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;)&lt;/span&gt;&lt;/span&gt;

hey -z 300s -c 250 -t 300 &lt;span class=&quot;pl-s&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;pl-smi&quot; color=&quot;var(--color-prettylights-syntax-storage-modifier-import)&quot; style=&quot;box-sizing: border-box;&quot;&gt;${url&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;:?&lt;/span&gt;}&lt;/span&gt;?sleep=100&amp;amp;prime=1000&amp;amp;bloat=1&lt;span class=&quot;pl-pds&quot; color=&quot;var(--color-prettylights-syntax-string)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; \
    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; kubectl get pods -n knative-interruptible&lt;/pre&gt;
  &lt;/div&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    You should be able to see the various signs of activity in the cluster using
    different methods, such as:
  &lt;/p&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      Running the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kn service describe mywork -n knative-interruptible&lt;/code&gt;&amp;nbsp;command to determine the current allocation of service replicas
      versus the target number of replicas.
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Observing the corresponding&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/ocp-service-deployment-allocating-pods.png&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;Deployment&lt;/code&gt;&amp;nbsp;resource&lt;/a&gt;&amp;nbsp;in the OCP &quot;Workloads -&amp;gt; Deployments&quot; tab and switching to
      the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;knative-interruption&lt;/code&gt;&amp;nbsp;project at the top.
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Listing the corresponding pods associated with the service with&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;kubectl get pods -n knative-interruptible&lt;/code&gt;.
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Once the&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;hey&lt;/code&gt;&amp;nbsp;utility returns, you should see an output like the one below with
    likely different numerical results:
  &lt;/p&gt;
  &lt;div class=&quot;highlight highlight-source-shell notranslate position-relative overflow-auto&quot; dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; overflow: auto; position: relative;&quot;&gt;
    &lt;pre style=&quot;background-color: var(--color-canvas-subtle); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; line-height: 1.45; margin-bottom: 0px; margin-top: 0px; overflow-wrap: normal; overflow: auto; padding: 16px; word-break: normal;&quot;&gt;Tue Oct 18 20:16:31 UTC 2022

Summary:
  Total:        300.1402 secs
  Slowest:      1.2196 secs
  Fastest:      0.0031 secs
  Average:      0.1113 secs
  Requests/sec: 2246.3932
  
  Total data:    66059521 bytes
  Size/request:    97 bytes

Response &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;time&lt;/span&gt; histogram:
  0.003 [1]     &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  0.125 [621740]&lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.246 [50065] &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;■■■
  0.368 [1104]  &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  0.490 [428]   &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  0.611 [306]   &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  0.733 [201]   &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  0.855 [101]   &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  0.976 [100]   &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  1.098 [114]   &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;
  1.220 [73]    &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;|&lt;/span&gt;


Latency distribution:
  10% &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;in&lt;/span&gt; 0.1034 secs
  25% &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;in&lt;/span&gt; 0.1039 secs
  50% &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;in&lt;/span&gt; 0.1045 secs
  75% &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;in&lt;/span&gt; 0.1055 secs
  90% &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;in&lt;/span&gt; 0.1128 secs
  95% &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;in&lt;/span&gt; 0.1667 secs
  99% &lt;span class=&quot;pl-k&quot; color=&quot;var(--color-prettylights-syntax-keyword)&quot; style=&quot;box-sizing: border-box;&quot;&gt;in&lt;/span&gt; 0.1957 secs

Details (average, fastest, slowest):
  DNS+dialup:    0.0000 secs, 0.0031 secs, 1.2196 secs
  DNS-lookup:    0.0000 secs, 0.0000 secs, 0.0200 secs
  req write:    0.0000 secs, 0.0000 secs, 0.0101 secs
  resp wait:    0.1112 secs, 0.0031 secs, 1.2196 secs
  resp read:    0.0000 secs, 0.0000 secs, 0.0010 secs

Status code distribution:
  [200]    674224 responses
  [502]    9 responses&lt;/pre&gt;
  &lt;/div&gt;
  &lt;h3 dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-tuning&quot; id=&quot;user-content-tuning&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Tuning
  &lt;/h3&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    Notice how the client in the previous example reported a few HTTP responses
    of &quot;502&quot;, which means those requests effectively failed. After
    troubleshooting the problem, I noticed that some pods were exceeding their
    memory reservation, already set at a rather lofty - for a serverless
    container - 256Mi of RAM.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    This small error rate is not a problem for an exploratory workload like
    this, especially when using a container image designed to stress the service
    boundaries through its&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;prime&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code style=&quot;background-color: var(--color-neutral-muted); border-radius: 6px; box-sizing: border-box; font-family: ui-monospace, SFMono-Regular, &amp;quot;SF Mono&amp;quot;, Menlo, Consolas, &amp;quot;Liberation Mono&amp;quot;, monospace; font-size: 13.6px; margin: 0px; padding: 0.2em 0.4em;&quot;&gt;bloat&lt;/code&gt;&amp;nbsp;query parameters. You can try different combinations that increase or
    improve the failure rates, knowing that higher values for these parameters
    will require higher container resource requests and possibly result in
    higher rates of HTTP error responses.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    When working with real workloads meant for a production environment, this
    type of setup with dynamic capacity allocation requires a firm grip on the
    performance characteristics of your container, chiefly among them:
  &lt;/p&gt;
  &lt;ol dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      Maximum number of concurrent requests per instance
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Container memory utilization while serving that maximum number of requests
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Container CPU utilization while serving that maximum number of requests
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      Time to readiness, counting the time between the pod being assigned to a
      node and all readiness probes returning their first successful reply.
    &lt;/li&gt;
  &lt;/ol&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    In general, you want to optimize these parameters for the best balance
    between quick response times and resource utilization and then reflect these
    parameters in the Knative service definition.
  &lt;/p&gt;
  &lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;!--more--&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
  &lt;h2 dir=&quot;auto&quot; style=&quot;background-color: white; border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-conclusion&quot; id=&quot;user-content-conclusion&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;Conclusion
  &lt;/h2&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    This article shows how the cluster auto-scaling and Knative services team up to
    run over interruptible cloud instances and generate significant cost savings
    for workloads with more relaxed service-level objectives.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    These savings are&amp;nbsp;&lt;em style=&quot;box-sizing: border-box;&quot;&gt;multiplied&lt;/em&gt;&amp;nbsp;over the life of the service, with the cluster autoscaling reducing
    fixed capacity allocation and the interruptible cloud instances reducing the
    hourly cost of that remaining capacity.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    For the variable cost portion, the hourly savings depend on the spot price
    of the instance at the time of the request. In the case of AWS, you can see
    a&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/blogs/raw/main/knative-interruptible/images/aws-spot-instance-savings.png&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;&quot;savings&quot; summary&lt;/a&gt;&amp;nbsp;at any point to give you an idea of how much you saved over the
    allocation of on-demand instances.
  &lt;/p&gt;
  &lt;p dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 16px; margin-top: 0px;&quot;&gt;
    For the fixed allocation part, Knative pairs well with the cluster
    autoscaler, with the scheduling of services using&amp;nbsp;&lt;a href=&quot;https://knative.dev/docs/serving/autoscaling/scale-to-zero/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;scale-to-zero&lt;/a&gt;&amp;nbsp;settings. In those scenarios, the reduced activity on an endpoint
    eventually translates to the deallocation of nodes reserved for that service
    (using the affinity and tainting techniques explained in this article,)
    producing significant cost savings over fixed allocation strategies for pods
    and nodes.
  &lt;/p&gt;
  &lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;!--more--&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
  &lt;h2 dir=&quot;auto&quot; style=&quot;background-color: white; border-bottom: 1px solid var(--color-border-muted); box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; line-height: 1.25; margin-bottom: 16px; margin-top: 24px; padding-bottom: 0.3em;&quot;&gt;
    &lt;a aria-hidden=&quot;true&quot; class=&quot;anchor&quot; href=&quot;#user-content-references&quot; id=&quot;user-content-references&quot; style=&quot;background-color: transparent; box-sizing: border-box; float: left; line-height: 1; margin-left: -20px; padding-right: 4px; text-decoration-line: none;&quot;&gt;&lt;svg aria-hidden=&quot;true&quot; class=&quot;octicon octicon-link&quot; height=&quot;16&quot; version=&quot;1.1&quot; viewbox=&quot;0 0 16 16&quot; width=&quot;16&quot;&gt;
        &lt;path d=&quot;M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z&quot; fill-rule=&quot;evenodd&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;References
  &lt;/h2&gt;
  &lt;ul dir=&quot;auto&quot; style=&quot;background-color: white; box-sizing: border-box; color: #24292f; font-family: -apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 16px; margin-bottom: 0px; margin-top: 0px; padding-left: 2em;&quot;&gt;
    &lt;li style=&quot;box-sizing: border-box;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/machine_management/index.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift - Machine Management&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/machine_management/creating_machinesets/creating-machineset-aws.html#machineset-non-guaranteed-instance_creating-machineset-aws&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift - Machine sets that deploy machines as Spot Instances&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://access.redhat.com/solutions/5268131&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift - How to add new nodes in OpenShift 4.x with taints using
          machineset configuration?&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/machine_management/applying-autoscaling.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift - Applying autoscaling to an OpenShift Container Platform
          cluster&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://access.redhat.com/solutions/5802541&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift - Setting node label with machineset during node
          creation&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://docs.openshift.com/container-platform/4.10/machine_management/creating_machinesets/creating-machineset-aws.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift - Machine sets that deploy machines as Spot Instances&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://docs.openshift.com/container-platform/4.11/serverless/develop/serverless-applications.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;OpenShift - Serverless applications&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://redhat-developer-demos.github.io/knative-tutorial/knative-tutorial/serving/knative-client.html&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Knative - OpenShift Knative tutorial&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;Kubernetes - Assigning Pods to Nodes&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://medium.com/swlh/beautiful-load-testing-with-k6-and-docker-compose-4454edb3a2e3&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;K6s - Beautiful Load Testing With K6 and Docker Compose&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://k6.io/docs/using-k6/k6-options/reference/#insecure-skip-tls-verify&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;K6s - Insecure skip TLS verify&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://aws.amazon.com/ec2/spot/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;AWS - EC2 Spot Instances&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://aws.amazon.com/getting-started/hands-on/amazon-eks-with-spot-instances/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;AWS - Amazon Elastic Kubernetes Service and Spot Instances&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://aws.amazon.com/about-aws/whats-new/2020/12/amazon-eks-support-ec2-spot-instances-managed-node-groups/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;AWS - Amazon EKS adds support for EC2 Spot Instances in managed node
          groups&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
    &lt;li style=&quot;box-sizing: border-box; margin-top: 0.25em;&quot;&gt;
      &lt;p dir=&quot;auto&quot; style=&quot;box-sizing: border-box; margin-bottom: 16px; margin-top: 16px;&quot;&gt;
        &lt;a href=&quot;https://aws.amazon.com/ec2/faqs/&quot; rel=&quot;nofollow&quot; style=&quot;background-color: transparent; box-sizing: border-box; text-decoration-line: none;&quot;&gt;AWS - Amazon EC2 - Billing - Spot Instances&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;/ul&gt;&lt;div&gt;&lt;span face=&quot;-apple-system, system-ui, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji&quot; style=&quot;color: #24292f;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, system-ui, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji&quot; style=&quot;color: #24292f;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;&lt;span&gt;&lt;!--more--&gt;&lt;/span&gt;
</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/6755856382382560509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/10/running-knative-services-on-aws-spot.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/6755856382382560509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/6755856382382560509'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/10/running-knative-services-on-aws-spot.html' title='Running Knative services on AWS spot instances'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-1501268685923929462</id><published>2022-09-12T15:00:00.006-07:00</published><updated>2022-09-28T13:20:50.697-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="productivity"/><category scheme="http://www.blogger.com/atom/ns#" term="programming"/><category scheme="http://www.blogger.com/atom/ns#" term="software"/><title type='text'>How to Outperform a 10x Developer</title><content type='html'>&lt;p&gt;&amp;nbsp;&lt;i&gt;(I originally posted this article on&amp;nbsp;&lt;a href=&quot;https://dnastacio.medium.com/how-to-outperform-a-10x-developer-fa1132807934&quot; target=&quot;_blank&quot;&gt;medium.com&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;ca3a&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;section class=&quot;section section--body&quot; name=&quot;ca3a&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;&lt;br /&gt;First awareness. Then productivity.&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;e50e&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;f611&quot;&gt;&lt;img alt=&quot;Software developer sitting at their desk, with ear phones on, and writing code. On the right, a huge expanse of a data-center, with operations teams interacting, several computer racks and antennas. There is a small dot in the expanse with a callout showing the developer on the left.&quot; class=&quot;graf-image&quot; data-height=&quot;686&quot; data-image-id=&quot;1*_ojHNsx2lWy5glZwQyDDOA.png&quot; data-width=&quot;1460&quot; height=&quot;301&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*_ojHNsx2lWy5glZwQyDDOA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;From a software developer’s perspective, the complexity of a production system makes it abstract and distant, so we tend to shut it out and focus on the immediate work of writing&amp;nbsp;code.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;730e&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@jeff-foster&quot; href=&quot;https://medium.com/@jeff-foster&quot; target=&quot;_blank&quot;&gt;Jeff Foster&lt;/a&gt; wrote a &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/ingeniouslysimple/the-origins-of-the-10x-developer-2e0177ecef60&quot; href=&quot;https://medium.com/ingeniouslysimple/the-origins-of-the-10x-developer-2e0177ecef60&quot; target=&quot;_blank&quot;&gt;great story&lt;/a&gt; on the origins of the expression “10x developer,” contrasting the value of &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/ingeniouslysimple/project-vs-product-thinking-b4971163f3dd&quot; href=&quot;https://medium.com/ingeniouslysimple/project-vs-product-thinking-b4971163f3dd&quot; target=&quot;_blank&quot;&gt;outsized code-writing skills against the ability to focus on the product&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7231&quot;&gt;From a DevOps perspective, its all-inclusive reach from development to operations demands collaboration. Focusing on the product trumps coding skills every time, not the least because sometimes not writing new code is the best decision for the product.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2136&quot;&gt;This story offers concrete examples where a better understanding of a production system can change how we see our roles as software developers and significantly improve how we design systems and write code.&lt;/p&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;c303&quot;&gt;&lt;strong class=&quot;markup--strong markup--h3-strong&quot;&gt;When quality is not&amp;nbsp;enough&lt;/strong&gt;&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5666&quot;&gt;Quality code and honed skills still matter, of course. Software developers should &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://opensource.com/article/17/5/30-best-practices-software-development-and-testing&quot; href=&quot;https://opensource.com/article/17/5/30-best-practices-software-development-and-testing&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;observe good practices&lt;/a&gt; such as automated linters, code reviews, unit testing, and many others. Still, writing great quality code fast is a small fraction of all the tasks required to bring a system to production and keep it alive.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;86b1&quot;&gt;In that sense, organizations should not spend too many resources finding and nurturing 10x developers. Firstly, they&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.simplethread.com/the-10x-programmer-myth/&quot; href=&quot;https://www.simplethread.com/the-10x-programmer-myth/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt; may not be actual 10x developers&lt;/a&gt;. Secondly, and most importantly: &lt;em class=&quot;markup--em markup--p-em&quot;&gt;sustained&lt;/em&gt; software development must include supporting material, such as design documentation and operating procedures. Those documents must be constantly reviewed and updated in collaboration with people using them. You can streamline the coordination activities, but the underlying human interactions and workflows will hardly happen 10x faster.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6c73&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Update on 9/22: &lt;/strong&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@hayavuk&quot; href=&quot;https://medium.com/@hayavuk&quot; target=&quot;_blank&quot;&gt;Hajime Vukelic&lt;/a&gt; added a comment to the story, pointing out that I made it sound like outsized individual performance is impossible or undesirable. I still think it is difficult in a DevOps practice, but his thoughtful reasoning stands on its own and also led me to read one of his personal stories, titled &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@hayavuk/whats-a-high-differential-developer-2fc42e2ee6a3&quot; href=&quot;https://medium.com/@hayavuk/whats-a-high-differential-developer-2fc42e2ee6a3&quot; target=&quot;_blank&quot;&gt;“What’s a high-differential developer”&lt;/a&gt;. I think it is an excellent addition to this general topic.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3219&quot;&gt;You want the developers who perform at a higher, yet attainable, level (1.2x developer?) so that other team members can understand and assimilate more productive techniques and behaviors.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;b5f1&quot;&gt;&lt;img alt=&quot;There are three sticky figures from left to right: a software developer on a desk, another one resembling a character in a show, and the last one is flying and has a cape. The character in a show and the flying character have labels indicating their “force multiplier,” of 10x and 27x, respectively, while the developer has a single “1x” multiplier crossed out and replaced with a “27x” label.&quot; class=&quot;graf-image&quot; data-height=&quot;478&quot; data-image-id=&quot;1*FqyoapeNTZvXWAjmXyj73Q.png&quot; data-width=&quot;1144&quot; height=&quot;267&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*FqyoapeNTZvXWAjmXyj73Q.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Growing talent is the better path toward productivity. The characters on the right are too unique and rare to make a significant impact across multiple&amp;nbsp;teams.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8756&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;cccb&quot;&gt;Lesson 1 — Greatness takes time: 27 times&amp;nbsp;more.&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2ee1&quot;&gt;I don’t mean “time” as in “decades of experience” — that helps too — but rather “time” as the actual time it takes to do great work.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2b5a&quot;&gt;Even the most talented developers sabotage themselves with poor estimations of how long it takes to go from a prototype to a sustainable system in production. I must emphasize the word “sustainable,” where on-call shifts produce few page-outs that &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;http://sourcepatch.blogspot.com/2021/09/asking-wrong-question-should-developers.html?view=magazine&quot; href=&quot;http://sourcepatch.blogspot.com/2021/09/asking-wrong-question-should-developers.html?view=magazine&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;even people who did not write the code&lt;/a&gt; can resolve.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;dc02&quot;&gt;My favorite technique to estimate the total cost of a feature in production is to create a working prototype and then &lt;em class=&quot;markup--em markup--p-em&quot;&gt;multiply the time spent on the prototype by 27&lt;/em&gt;. That is right; if it takes me two days to develop a prototype, it may take nearly three months (2x27=54 business days) of combined effort across the whole team to have it humming along in production.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c15e&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Update on 9:22&lt;/strong&gt;: User &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@liquidanalytics&quot; href=&quot;https://medium.com/@liquidanalytics&quot; target=&quot;_blank&quot;&gt;Liquid Analytics&lt;/a&gt; made an excellent point in the comment section about the 27x multiplier becoming a possible inhibitor to meaningful progress. I should have mentioned that the idea is to deploy the prototype using modern “test in production” approaches, such as &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://trunkbaseddevelopment.com/&quot; href=&quot;https://trunkbaseddevelopment.com/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;trunk-based development&lt;/a&gt; behind &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.split.io/glossary/dark-launch&quot; href=&quot;https://www.split.io/glossary/dark-launch&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;dark launches&lt;/a&gt; or &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.atlassian.com/continuous-delivery/principles/feature-flags&quot; href=&quot;https://www.atlassian.com/continuous-delivery/principles/feature-flags&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;feature flags&lt;/a&gt;.&lt;/p&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;da0e&quot;&gt;&lt;strong class=&quot;markup--strong markup--h4-strong&quot;&gt;&lt;em class=&quot;markup--em markup--h4-em&quot;&gt;Why 27x?&lt;/em&gt;&lt;/strong&gt;&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;faa5&quot;&gt;Frederick Brooks Jr. explained the first “9x” in &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://archive.org/details/MythicalManMonth&quot; href=&quot;https://archive.org/details/MythicalManMonth&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“The Mythical Man-Month,”&lt;/a&gt; his landmark set of essays on software development in book form.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6389&quot;&gt;The first 3x multiplier is the cost of going from running code (the book uses the term “program,” characteristic of the time) to a reliable application (the book used the term “program product.”)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7a43&quot;&gt;The second 3x multiplier comes from the additional testing needed to turn that reliable application into a system (a “system product.”)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;bbe2&quot;&gt;Brooks covered the aspects of creating software to be handed to customers for on-premise deployment — characteristic of IBM’s business model at the time. As such, it excludes the costs associated with operational aspects, where I add the final 3x factor — based on my experience in operations engineering, so your multiplier may vary — to turn a system into an operable Cloud-based service.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;f8fb&quot;&gt;&lt;img alt=&quot;Three-dimensional cube partitioned across each dimension: (1) individual program quality, (2) integration with other systems, and (3) deployment in production. There is an arrow labeled “3x” between each partition, and the smaller cube where all partitions intersect is labeled “production system”. That cube contains a series of small rectangles depicting computers, and they are connected to an antenna. A group of 3 people, representing operations people, stand next to that complex system.&quot; class=&quot;graf-image&quot; data-height=&quot;1198&quot; data-image-id=&quot;1*Cc7Rqo9tCuSDNozLSzRt_g.png&quot; data-width=&quot;1424&quot; height=&quot;538&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*Cc7Rqo9tCuSDNozLSzRt_g.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Brooks explained why something ready to be deployed at a customer site takes nine times the effort of creating a prototype. I added the extra 3x factor for deploying and maintaining the&amp;nbsp;system.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5afe&quot;&gt;That final multiplier includes development activities such as:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;6865&quot;&gt;Instrumenting the system for observability&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;b333&quot;&gt;Documenting operational procedures based on the system design&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;82ad&quot;&gt;Development and upkeep of the continuous deployment pipeline&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;28bc&quot;&gt;Integration testing with other cloud provider services.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;87a5&quot;&gt;Combining all multipliers (3x3x3) gives us the 27x additional cost to take a prototype to production.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e64d&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why it matters:&lt;/strong&gt; While a seasoned developer may not undershoot the sizing of a new feature by the entire 27x multiplier, anything beyond a &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://fibery.io/blog/software-development-time-estimation/&quot; href=&quot;https://fibery.io/blog/software-development-time-estimation/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;2x or 3x factor &lt;/a&gt;is guaranteed to create intractable surprises across the team and, more importantly, deprive you of the time needed to add and validate everything you need to avoid handing a nightmare to the operations team.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;3612&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;ab4c&quot;&gt;Lesson 2 — Operations engineering trumps&amp;nbsp;art&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6a5c&quot;&gt;By all means, art has its place, and some corners of the system may look clever or exquisite, but ultimately &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://en.wikipedia.org/wiki/Form_follows_function&quot; href=&quot;https://en.wikipedia.org/wiki/Form_follows_function&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;form follows function&lt;/a&gt;, and the function of a production system is to run software that meets requirements and cost objectives.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2ff9&quot;&gt;This section covers lessons learned in operations and how they should affect design and coding activities, accounting for a portion of that 27x multiple.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7520&quot;&gt;The section does not cover the entire spectrum outside code development, which would make this story too long for now.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0a72&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;More components. More cost. Check everyone’s budget.&lt;/strong&gt; Taking operational costs into account during design and architecture is the most important lesson I have ever learned in my time in operations. Any &lt;em class=&quot;markup--em markup--p-em&quot;&gt;new&lt;/em&gt; component in the system alters the cost structure of operating that system, so you need to ask yourself whether that component is removing more cost than it is adding and be ready to forego adding something that looks &lt;em class=&quot;markup--em markup--p-em&quot;&gt;really&lt;/em&gt; fun into the system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;16ec&quot;&gt;After all, the same world where CFOs (rightfully) tell you that &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://twitter.com/KurtisHanni/status/1560986912613072899&quot; href=&quot;https://twitter.com/KurtisHanni/status/1560986912613072899&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;bringing in more revenue trumps cutting expenses&lt;/a&gt; is inhabited by developers who will abstract a 50ms SQL query into a microservice-wrapped series of paginated RESTful calls (true story.)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8599&quot;&gt;I don’t mean to take a reactionary approach to change, but this is an area where one needs to find ways to collaborate or, at a minimum, consult with the operations team.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f126&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;World-class status and health endpoints.&lt;/strong&gt; No one can afford to fumble after the system status during an outage, especially in micro-service architectures with hundreds of components.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a70a&quot;&gt;A production system needs an overall health point aggregating the health from various dependencies. The idea is that an operator can quickly assess (1) which parts of the system are not working and (2) which dependencies are not working. The “why” part comes later.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3920&quot;&gt;I listed my suggestions for designing health endpoints in my article on &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;http://sourcepatch.blogspot.com/2021/12/the-art-and-science-of-probing.html&quot; href=&quot;http://sourcepatch.blogspot.com/2021/12/the-art-and-science-of-probing.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;readiness and liveness for Kubernetes containers&lt;/a&gt; — most of the recommendations in that article also apply to non-Kubernetes systems.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;53e7&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Log errors from the reader’s perspective. &lt;/strong&gt;Once an operator realizes that the system is not entirely healthy, the next step is understanding what is causing it and how to fix it.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;98e8&quot;&gt;At an elementary level, something should be happening, and it is not. From the perspective of the person reading a log message, the most helpful log messages follow a template like this:&lt;/p&gt;&lt;pre class=&quot;graf graf--pre&quot; name=&quot;6b1f&quot;&gt;[ERROR|WARNING|INFO]&lt;em class=&quot;markup--em markup--pre-em&quot;&gt;: &lt;/em&gt;[Component X]&lt;em class=&quot;markup--em markup--pre-em&quot;&gt; attempted to &lt;/em&gt;[take action Y]&lt;em class=&quot;markup--em markup--pre-em&quot;&gt;, which returned &lt;/em&gt;[response Z]&lt;em class=&quot;markup--em markup--pre-em&quot;&gt;.&lt;/em&gt;&lt;/pre&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a834&quot;&gt;That format may seem evident at first — it looks like a regular subject-verb-object construct — but it is the terminology that matters the most:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;2454&quot;&gt;Is &lt;em class=&quot;markup--em markup--li-em&quot;&gt;“component X”&lt;/em&gt; something that exists in the system documentation?&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;ac37&quot;&gt;Is that &lt;em class=&quot;markup--em markup--li-em&quot;&gt;“action Y”&lt;/em&gt; something accessible to the reader?&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;6504&quot;&gt;Is &lt;em class=&quot;markup--em markup--li-em&quot;&gt;“response Z”&lt;/em&gt; mentioned somewhere in a troubleshooting section?&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;1d1d&quot;&gt;&lt;img alt=&quot;On the right, picture with a sheet of paper representing a log file. On the left, four individual smaller sheets of paper representing a separate page of the product documentation. The log sheet on the left has six symbols called out from the rest of the text, with only four of them having an arrow connecting them to the product document sheets. The remaining 2 symbols, without any arrow linking them to the product documentation, have question marks next to them.&quot; class=&quot;graf-image&quot; data-height=&quot;401&quot; data-image-id=&quot;1*FYSpcim_B-fd4fdUKtamPw.png&quot; data-width=&quot;386&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*FYSpcim_B-fd4fdUKtamPw.png&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Log messages can help explain the system behavior, but only if the message contents match the contents of the official documentation, even if forums unaffiliated with the product fill some&amp;nbsp;gaps.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2ba3&quot;&gt;I have read my fair share of error messages that made me thankful that someone spent the time adding them to the code but gave me pause about referencing file names and library calls that only meant something to their authors. Those internal references should be in dedicated trace files or marked with a “debug” prefix for easy filtering.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1313&quot;&gt;Ultimately, every log message must lead to a clear resolution step that does not involve contacting the message’s author or reading the source code.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0f4b&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Write system documentation:&lt;/strong&gt; Writing documentation forces you to structure your understanding of the system into a new medium. The activity brings many benefits to the system besides the imperative of telling people how to install, monitor, secure, or troubleshoot the system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7327&quot;&gt;The act of writing requires authors to &lt;em class=&quot;markup--em markup--p-em&quot;&gt;think through aspects of the system&lt;/em&gt; that may be difficult to explain.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;483c&quot;&gt;Often, that difficulty may indicate potential design flaws, such as struggling to explain the correct order of installation of all components. Other times, the struggle may be due to “underdeveloped” areas of the product requiring long stretches of pseudo-code instructions for the reader (&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“…then click here, type this, wait a few seconds, then a panel will pop up, find a button named…”&lt;/em&gt;)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8652&quot;&gt;When done correctly, documentation also acts as a gathering point for collaborators that may have the willingness to donate their knowledge but not the time to figure out how to do it. These types of contributions are a huge productivity boost for the entire ecosystem (developers and users) and tend to get otherwise lost in team channels and private conversations.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8689&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Timebox calls to remote components&lt;/strong&gt;. In distributed systems, we know better than depend on remote agents always to respond quickly and reliably. Still, we often go with default timeout settings in client libraries and utilities without giving it a second thought because we assume their developers already figured out the magic settings that work for everybody.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3c49&quot;&gt;That is a common oversight in a world of libraries and utilities shipped with sensible defaults and systems adopting the latest design and operational techniques for maximum availability. The misplaced confidence in the resulting system works out until one of those systems fails, leaving your component unconditionally stuck on a &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://man7.org/linux/man-pages/man7/tcp.7.html&quot; href=&quot;https://man7.org/linux/man-pages/man7/tcp.7.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;2-hour wait&lt;/a&gt; for a TCP timeout.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2bc7&quot;&gt;Always look for remote calls in the code and make sure you know their limits and how your code will handle those limits:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;fed7&quot;&gt;Maximum connection response time&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;ae4e&quot;&gt;Maximum request response time&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;4901&quot;&gt;Maximum number of retries&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;ac88&quot;&gt;&lt;img alt=&quot;Two tall boxes side by side, with four arrows pointing from the box on the left to the box on the right. Top arrow indicates a failed connection, second arrow indicates a successful connection, third arrow indicates a failed “send” operation and, finally, the fourth arrow indicates a successful transmission, leading to a final success “checkmark” about the troubled communication being ultimately successful.&quot; class=&quot;graf-image&quot; data-height=&quot;382&quot; data-image-id=&quot;1*hEVwIAvAuADROKlJV8CKhg.png&quot; data-width=&quot;546&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*hEVwIAvAuADROKlJV8CKhg.png&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Remote systems or the network paths between your system and the remote system may be so reliable that we start treating them as function calls in local memory. Scrutinize all libraries and network stacks to find their tolerance for connectivity problems and error codes in case of problems.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;44dd&quot;&gt;Creating an effective retry policy for remote calls is a welcome improvement to any system. Still, it has the potential of obscuring the visibility into looming problems, such as masking a steady worsening of response times until they finally exceed the maximum limits, leading me to the next point.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;954a&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Telemetry, observability, and distributed tracing&lt;/strong&gt;: There is more to handling outages than looking at system status and log entries. There is also more to operations than handling outages, such as proactively looking at the system’s telemetry of internal metrics, traces, and log entries.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0f99&quot;&gt;Many platforms already generate a wealth of telemetry data with &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://opentelemetry.io/docs/instrumentation/&quot; href=&quot;https://opentelemetry.io/docs/instrumentation/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;minimum instrumentation in the source code&lt;/a&gt;. However, one still needs quite a bit of telemetry-specific code mixed with the source code, especially for metrics.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;d623&quot;&gt;&lt;img alt=&quot;Large cylinder on the left, full of interconnected computer components, such as computer racks, antennas, and even a conveyor belt. Small box on the right, with big positive checkmark, representing a dashboard. A confused system admin stands on the left, staring at the cylinder, while another system administrator looks reassured to the dashboard.&quot; class=&quot;graf-image&quot; data-height=&quot;562&quot; data-image-id=&quot;1*UFTHIWhs8WGdpiNGvaGPrw.png&quot; data-width=&quot;1412&quot; height=&quot;255&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*UFTHIWhs8WGdpiNGvaGPrw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Each system component may not tell you whether it is meeting its goals. Making the code generate metrics takes extra effort, aggregating them into an actionable dashboard for the operations team.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9f2f&quot;&gt;Also, ensure you (and other developers) have regular access to a local setup of the telemetry framework used in the system’s operations. Many frameworks support local execution in your workstation or a free trial cloud-based account. A uniform setup that allows a seamless transition from local to remote environments takes development, validation, documentation, and upkeep. Creating such environments can be a lot of fun, but it costs time and money too.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;56ba&quot;&gt;I can’t emphasize enough how &lt;em class=&quot;markup--em markup--p-em&quot;&gt;even the most experienced and self-confident developers always learn something new or surprising when looking at the telemetry of their code&lt;/em&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;41bc&quot;&gt;Taking it to the next level, &lt;em class=&quot;markup--em markup--p-em&quot;&gt;work with your operations team to ensure a data-sharing arrangement with the operations team&lt;/em&gt;, dedicating special attention and effort to aspects such as data anonymization and access.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;209e&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Beware of queueing systems.&lt;/strong&gt; Writing queuing systems is fun, and designing the architectural diagrams can be exciting (and enticing), but most people seriously misjudge the cost of adding queuing patterns into a system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;03b2&quot;&gt;I know there are legitimate use cases for queueing systems, like high-volume transactions — as in millions of messages per day — where the calling component cannot wait for the response and only cares that the transaction eventually gets processed within a reasonable time.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0174&quot;&gt;However, if you are not dealing with those use cases, you may want to seriously reconsider the inclusion of asynchronous message processing into the system. That communication pattern adds costs that stretch across the entire length of a business transaction between a message producer “A” and a message consumer “B.” Here are just a few examples of that extra complexity:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;da55&quot;&gt;Operational procedures for system administrators to deal with queue sizes exceeding certain limits&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;1abe&quot;&gt;Extra design and code to deal with expiring messages.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;c157&quot;&gt;Operational procedures for handling messages sent to dead-letter queues after expiration.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;d288&quot;&gt;Extending the system to manage dead-letter queues&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;0fa4&quot;&gt;Handling &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://microservices.io/patterns/observability/distributed-tracing.html&quot; href=&quot;https://microservices.io/patterns/observability/distributed-tracing.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;distributed tracing&lt;/a&gt; for business transactions spanning over a message delivery.&lt;/li&gt;&lt;/ul&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;21be&quot;&gt;Lesson 3 — Thread the quad: code, build, support,&amp;nbsp;operate&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b0fd&quot;&gt;While a long career may gradually teach you about different areas of a DevOps practice, you can expedite your growth by intentionally rotating across development, integration, support, and operations. The idea is to learn how things work and how to build software that works well in each significant area of the engineering cycle.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9e68&quot;&gt;And once you get to know the people and workflows in those areas, it becomes easier to contribute outside your core expertise with less technical and social friction.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;675a&quot;&gt;Mid-career and senior developers may not be as inclined to change job roles, but their experience allows them to learn faster. A temporary rotation of a few weeks, a shared project, or even access to customer support tickets and incident reports may work just as well.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;8b8e&quot;&gt;&lt;img alt=&quot;There are four sections arranged in a circle. Each section represents development, build, support, and operations, respectively. Each section has an arrow pointing to the next section, with a person performing that respective role.&quot; class=&quot;graf-image&quot; data-height=&quot;1094&quot; data-image-id=&quot;1*u3mRMPDcgoRmu7lvuALkaw.png&quot; data-width=&quot;1374&quot; height=&quot;510&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*u3mRMPDcgoRmu7lvuALkaw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;A DevOps practice encourages more access and insight into different areas. Take a step further and rotate into those areas, even briefly, to understand how various software characteristics affect their&amp;nbsp;work.&lt;/figcaption&gt;&lt;/figure&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;137d&quot;&gt;&lt;strong class=&quot;markup--strong markup--h4-strong&quot;&gt;Case study 1&amp;nbsp;(build)&lt;/strong&gt;.&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;75b0&quot;&gt;We had a team primarily responsible for evolving and maintaining the build system in a previous project. Building (compiling and packaging) the entire code base in a local workstation took about two minutes. In contrast, the same operation in the build cycle took a seemingly eternal fifteen minutes.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;eed1&quot;&gt;One of the developers outside the build team spent an afternoon adding various log entries to the build scripts to isolate the problem, narrowing the likely cause to the steps where the build wrote compiled binaries to disk. Somehow, disk write operations seemed to take orders of magnitude longer in the build system than in a local workstation (and yes, the build machine had SDD storage&amp;nbsp;:-)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4cbd&quot;&gt;The build team analyzed those findings and attempted different alternatives (some of those outside the Unix skillset from the original developer,) landing on the final solution of increasing the memory allocation on the VMs and moving the temporary directories for each build to an in-memory filesystem (&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://en.wikipedia.org/wiki/Tmpfs&quot; href=&quot;https://en.wikipedia.org/wiki/Tmpfs&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;tmpfs&lt;/a&gt;.)&lt;/p&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;3750&quot;&gt;&lt;strong class=&quot;markup--strong markup--h4-strong&quot;&gt;Case study 2 (operations)&lt;/strong&gt;.&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6573&quot;&gt;I once co-managed the PagerDuty escalation policies and alerting rules for our entire organization — a few hundred people — for a few months. Sometimes, depending on vacation schedules and local holidays, that meant receiving urgent direct messages requesting that I enable alerting triggers in portions of the system outside my immediate scope.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3b7c&quot;&gt;I would always ask a few questions before pushing the buttons, such as:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li graf--startsWithDoubleQuote&quot; name=&quot;d6d8&quot;&gt;“When will the components generating these new alerts be deployed?”&lt;/li&gt;&lt;li class=&quot;graf graf--li graf--startsWithDoubleQuote&quot; name=&quot;e5f7&quot;&gt;“I don’t see a playbook link in the description. Does the ops team know where to look for one?”&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4257&quot;&gt;Without going into the occasional mix of bewildering answers, that (part-time) assignment taught me valuable lessons about the importance of managing the total number of types of alerts in a system, the cost-benefit of adding new components to a production system, and the absolute imperative of involving operations teams in architectural decisions.&lt;/p&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;750a&quot;&gt;Lesson #4 — Intentional learning: Learn with every&amp;nbsp;task.&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e9d1&quot;&gt;At this point, you know how to secure the time to write code that is ready for production and the things you need to include in that code.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8fd6&quot;&gt;That is a long list of things; you don’t want to wait decades to acquire those skills organically, &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.edsurge.com/news/2020-05-05-researcher-behind-10-000-hour-rule-says-good-teaching-matters-not-just-practice&quot; href=&quot;https://www.edsurge.com/news/2020-05-05-researcher-behind-10-000-hour-rule-says-good-teaching-matters-not-just-practice&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;the “10000-hour” rule&lt;/a&gt; notwithstanding.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0780&quot;&gt;We always learn something while performing a task, but &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://learntechasia.com/intentional-learning-global-reskilling-emergency/&quot; href=&quot;https://learntechasia.com/intentional-learning-global-reskilling-emergency/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;intentional learning&lt;/a&gt; means going beyond getting the work done and figuring out why something works and how to improve it.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7710&quot;&gt;A web search may give you a precise answer to a specific problem, and one can learn a lot that way, but with intentional learning, the idea is to go beyond ready-made solutions:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;dc15&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Browse&lt;/strong&gt;. If the solution involves a patterned solution for a framework, such as a specific set of resources for Terraform, go back to &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://registry.terraform.io/browse/providers&quot; href=&quot;https://registry.terraform.io/browse/providers&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;browse the complete definition for those resources&lt;/a&gt; and maybe browse adjacent resources from the same provider.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;9fd3&quot;&gt;If the solution involves a utility with specific parameters, go back to the utility’s manual to study those parameters and also skim over the other parameters. The idea is not to memorize but to &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;index&lt;/strong&gt; them in your mind, especially in the cases such as “&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.gnu.org/software/gawk/manual/gawk.html&quot; href=&quot;https://www.gnu.org/software/gawk/manual/gawk.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;awk&lt;/a&gt;,” where the manual can be an entire book.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;b707&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Explain&lt;/strong&gt; what you learned. For source code, pull out the “rubber duck” and explain the source code to an inanimate object. For concepts, you may even skip finding someone else and use the &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://en.wikipedia.org/wiki/Learning_by_teaching&quot; href=&quot;https://en.wikipedia.org/wiki/Learning_by_teaching&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Feynman technique&lt;/a&gt;, pretending you are presenting that concept to a child.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;422e&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Write&lt;/strong&gt; about the subject. Writing is a more intentional form of learning, helping you consolidate and expand your knowledge of a concept (maybe writing an article,) interrelated concepts (using something like a technical paper,) or an entire domain (for example, writing a book.) Writing goes far beyond learning so that it may be more helpful in organizing adjacent bits of knowledge in your head. If you do decide to take on this exciting activity, make sure to read &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.heinrichhartmann.com/posts/writing/&quot; href=&quot;https://www.heinrichhartmann.com/posts/writing/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“Writing for Engineers”&lt;/a&gt;, by Heinrich Hartmann.&lt;/li&gt;&lt;/ol&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;2d3a&quot;&gt;&lt;img alt=&quot;Sticky figure resembling the Superman character of the comic books.&quot; class=&quot;graf-image&quot; data-height=&quot;214&quot; data-image-id=&quot;1*cLBC668IyHkB7LkQvSaU1A.png&quot; data-width=&quot;176&quot; src=&quot;https://cdn-images-1.medium.com/max/1600/1*cLBC668IyHkB7LkQvSaU1A.png&quot; /&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;1fff&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Read the product guides? Who has time for that?”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4cc3&quot;&gt;I realize this is the age of googling “how-to-make-this-error-message-go-away,” which makes a lot of sense during a time crunch. Still, you don’t learn much from those kinds of shortcuts.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;24bd&quot;&gt;Here I must quote Stephen King, one of the most successful fiction authors of all time, who offered this bit of tough-love advice for &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://stephenking.com/works/nonfiction/on-writing-a-memoir-of-the-craft.html&quot; href=&quot;https://stephenking.com/works/nonfiction/on-writing-a-memoir-of-the-craft.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;aspiring writers&lt;/a&gt;:&lt;/p&gt;&lt;blockquote class=&quot;graf graf--blockquote graf--startsWithDoubleQuote&quot; name=&quot;15de&quot;&gt;“If you don’t have time to read, you don’t have the time (or the tools) to write. Simple as that.”&lt;/blockquote&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;89f5&quot;&gt;If you do not carve out time from the schedule to explore the technology used in your projects and expand upon it, you restrict yourself to learning just enough to complete your immediate tasks. That dynamic becomes self-reinforcing when people around you assume you are only capable of those same tasks. And it doesn’t take long for those assumptions to become justified.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fc1c&quot;&gt;That “carving out” of time may be more or less challenging depending on different situations, but awareness is a starting point. Sometimes you may constantly be doubling down on taking on repetitive (yet valuable) tasks because it is more comfortable. At other times your organization may become comfortable with someone doing a repetitive chore more efficiently than anyone else. Regardless of the situation,&lt;em class=&quot;markup--em markup--p-em&quot;&gt; recognizing that you are no longer learning something new in every task is the first step.&lt;/em&gt;&lt;/p&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;d61a&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ffa4&quot;&gt;A DevOps practice covers many distinct and extensive disciplines, which leads people to specialize in a given field, such as software development, continuous delivery, or operations.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;76bf&quot;&gt;Sometimes that narrowing of interests and purpose happens before people get a chance to explore other areas, so resist the urge and pressure to specialize early in your career. As an organization, balance the productivity that comes from people possibly overstaying in a role with the benefits of a &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://wa-shoku.info/jinji-ido-the-notorious-system-of-annual-rotations/&quot; href=&quot;https://wa-shoku.info/jinji-ido-the-notorious-system-of-annual-rotations/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Japanese-style approach of yearly rotations&lt;/a&gt; — perhaps not on a fixed schedule.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;82d5&quot;&gt;Early in your career, work with your management team to “intern” in coding, delivery, and operations. That kind of rounded experience is precious and exceedingly rare. It will help you multiply your potential in any area you choose to contribute, whether as a programmer, system architect, UX designer, technical account manager, infrastructure engineer, or any other role you may favor.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4309&quot;&gt;The willingness to understand what makes a product better from different angles and blend those lessons into your daily routine is a superpower far beyond anything even an actual 10x developer can muster in a niche area.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b66a&quot;&gt;Ultimately, these lessons come from personal experience, and every path is different. I welcome feedback in the comment section and promise to incorporate them appropriately into the main story.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/1501268685923929462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/09/how-to-outperform-10x-developer.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/1501268685923929462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/1501268685923929462'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/09/how-to-outperform-10x-developer.html' title='How to Outperform a 10x Developer'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>United States</georss:featurename><georss:point>37.09024 -95.712891</georss:point><georss:box>8.780006163821156 -130.869141 65.400473836178847 -60.556641</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-1192508289884721711</id><published>2022-06-29T17:00:00.016-07:00</published><updated>2022-07-01T10:56:50.173-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cost"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="operations"/><category scheme="http://www.blogger.com/atom/ns#" term="saas"/><title type='text'>Are you spending too much on Kubernetes?</title><content type='html'>&lt;p&gt;&amp;nbsp;&lt;i&gt;(I originally posted this article on&amp;nbsp;&lt;a href=&quot;https://dnastacio.medium.com/are-you-spending-too-much-on-kubernetes-179d703ec5c5?source=friends_link&amp;amp;sk=94690b0fd813bba7802a67a4f9b1e374&quot; target=&quot;_blank&quot;&gt;medium.com&lt;/a&gt;)&lt;/i&gt;&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;ca3a&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;section class=&quot;section section--body&quot; name=&quot;ca3a&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;6bd1&quot;&gt;Are you spending too much on Kubernetes?&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9214&quot;&gt;Probably, yes.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b887&quot;&gt;Anyone running a large fleet of Kubernetes clusters knows it takes sustained investment in hardware and operations personnel to keep everything online. That level of investment keeps Kubernetes in a rarefied layer of architecture diagrams reserved for companies managing large environments, often in regulated industries that need to run them on-premises.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;dfa7&quot;&gt;When the choice was Kubernetes versus Docker, &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://diginomica.com/docker-loses-first-mover-advantage-kubernetes&quot; href=&quot;https://diginomica.com/docker-loses-first-mover-advantage-kubernetes&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;the decision to embrace Kubernetes was straightforward&lt;/a&gt;, but several waves of new and sophisticated managed services invalidated many assumptions supporting those decisions, from cost to security to reliability.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3a3f&quot;&gt;Nowadays, many viable alternatives exist to schedule container-based workloads without running the entire cluster stack from the ground up.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;9240&quot;&gt;&lt;img alt=&quot;Large box representing a Kubernetes cluster. The box is split in 3 horizontal slices, a top slide for pods scheduled by developers, a middle slice for all Kubernetes components (etcd, nodes, kubelet, etc,) and a bottom slice for all the hardware supporting the cluster.&quot; class=&quot;graf-image&quot; data-height=&quot;704&quot; data-image-id=&quot;1*drRZ56ddtN6YnuY54cQ5Nw.png&quot; data-is-featured=&quot;true&quot; data-width=&quot;1008&quot; height=&quot;447&quot; src=&quot;https://cdn-images-1.medium.com/max/1280/1*drRZ56ddtN6YnuY54cQ5Nw.png&quot; title=&quot;It takes many different skills across different layers of abstractions to run a Kubernetes cluster.&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;It takes many different skills across different layers of abstractions to run a Kubernetes cluster.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3dfb&quot;&gt;I compiled some common themes on the most cost-effective and frictionless ways of running containers, inside a Kubernetes cluster or not, offering a landscape view of what is available to get there.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;9400&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;bd55&quot;&gt;How much does a product really&amp;nbsp;cost?&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;92c3&quot;&gt;Before discussing whether it still makes sense for you to run entire Kubernetes clusters on your own, it is essential to break down the significant phases of developing a product.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0b71&quot;&gt;Different people group those phases in different ways, but let’s use a generic arrangement as the backdrop for this story:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;2b73&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Design&lt;/strong&gt;. End-user experience, specification of system components, and their interactions.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;7725&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Development&lt;/strong&gt;. Coding, functional testing, documentation for end-users, and documentation for system integrators. It also includes the continuous integration pipeline that supports development activities.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;eaed&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Deployment&lt;/strong&gt;. Rollout development releases to production. It includes the continuous delivery pipeline.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;1bf9&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Operations&lt;/strong&gt;. Everything related to running the system, including hardware and personnel.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;2d74&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Support&lt;/strong&gt;. Deals with product failures at the customer’s hands.&lt;/li&gt;&lt;/ol&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;3562&quot;&gt;&lt;img alt=&quot;Box with 5 layers, from top to bottom: Design, Development, Deployment, Operations. Support.&quot; class=&quot;graf-image&quot; data-height=&quot;858&quot; data-image-id=&quot;1*QQpEMcGq3esELyq4fANrFg.png&quot; data-width=&quot;1072&quot; height=&quot;512&quot; src=&quot;https://cdn-images-1.medium.com/max/1280/1*QQpEMcGq3esELyq4fANrFg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;People participating in a product cycle often do not consider all parts of the business when making decisions. Product owners must continually assess the cost of an opportunity (or new feature) across all&amp;nbsp;layers.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9492&quot;&gt;Note that different teams and organizations may co-own these stages. For instance, a customer purchasing software as a license owns most of the “deployment” and “operations” stages.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;34d8&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;da19&quot;&gt;&lt;strong class=&quot;markup--strong markup--h3-strong&quot;&gt;Lesson #1: Money is cheap. Time is&amp;nbsp;not.&lt;/strong&gt;&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4f3e&quot;&gt;When discussing resources, we must acknowledge that money and time are intertwined.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;946c&quot;&gt;Adding capital to any system takes good credit and a reasonable business plan. Adding more “time” resources to a system, on the other hand, can take many forms. For instance, you can hire a consultancy, hire more people, or procure tools and services that increase productivity. Paradoxically, adding more “time” capacity into a product cycle takes effort and time. In short, you cannot increase your “time” capacity as quickly as you can increase your money supply.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e3cd&quot;&gt;When making decisions that shift costs from one product stage to another, consider the nature of the shift and ask yourself:&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;5c04&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Will it increase capital or time expenditures?”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2300&quot;&gt;It is essential to realize that decisions in the early stages of the cycle disproportionately affect the later stages. Adding an off-the-shelf middleware component during the “Design” stage may lower the costs during the “Development” stage but also increase the expenses during the “Operations” stage. I covered that scenario in “&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;http://sourcepatch.blogspot.com/2021/09/asking-wrong-question-should-developers.html&quot; href=&quot;http://sourcepatch.blogspot.com/2021/09/asking-wrong-question-should-developers.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Asking the wrong question: Should developers be on call?&lt;/a&gt;”.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fe0a&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Takeaway&lt;/strong&gt;: Keep focusing on opportunities &lt;em class=&quot;markup--em markup--p-em&quot;&gt;as long as&lt;/em&gt; you are still managing time. If you run out of capital, you can get a loan, maybe dilute ownership, and try again. On the other hand, when you run out of people, it is the end of the line.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;a1d9&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;7c76&quot;&gt;Lesson #2: 90% of nothing is&amp;nbsp;nothing&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;56c0&quot;&gt;People specialized in one stage of the product cycle generally lack awareness of what matters most in other areas and tend to focus almost exclusively on improvements in their field of expertise.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7c53&quot;&gt;Improvements to the system architecture may sound great, such as shifting from fixed pod allocation in a Kubernetes cluster to dynamic container scheduling using a managed container service. Many of these improvements are indeed great, but we must always pause for a moment to consider the impact on subsequent stages of the product lifecycle.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;686c&quot;&gt;For instance, if your product is heavy on R&amp;amp;D, such as a medical decision platform, and the IaaS bill represents only 5% of the overall budget, even a 50% reduction in those costs will not make a big difference, especially when you factor in the investment required to achieve those savings.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;cea9&quot;&gt;In that scenario, optimization efforts should start with the “Development” stage, not with the “Operations” stage. While it may be difficult for development infrastructure-minded folk like us to accept it, there are cases where something like an improved spreadsheet template can do more good than revamping parts of the system architecture. The incentives that keep technical people from making that kind of trade-off deserve their own story.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2ecb&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Takeaway&lt;/strong&gt;: Kubernetes adoption is a means to an end (running workloads,) not the only way, even for heavy adopters. On any given business, many vital processes still run elsewhere, are more critical, and consume more resources than a fleet of Kubernetes clusters.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;18ad&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;d1f5&quot;&gt;Lesson #3: Consider a managed Kubernetes service&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3a7b&quot;&gt;Kubernetes is great at further virtualizing a data center into a well-established set of portable APIs, which significantly simplifies the ownership of static resources, but you still own everything. When a storage disk fails, the corresponding persistence volumes in the cluster also fail, and you need people who understand both to diagnose and fix the problems in each layer.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2176&quot;&gt;To stress the point, I was writing a Terraform template just the other day to create all the IaaS resources required to install a Kubernetes cluster. The final count was nearly one hundred resources, covering DNS records, subnets, security groups, load balancers, network gateways, and many others. The template became so extensive that it now requires a dedicated CI process to validate changes before applying them to the production system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0db4&quot;&gt;With a managed Kubernetes service, you no longer own the underlying infrastructure resources, such as VPC (virtual private clouds,) virtual machines, disks, and networking. That transition shifts administrative costs (less time chasing infrastructure resources) to runtime costs (the service provider charges you a premium to operate all the infrastructure.)&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;3025&quot;&gt;&lt;img alt=&quot;Copy of the first picture with the 3 layers of a box showing containers, Kubernetes components, and then infrastructure components. The middle and bottom layers have lock signs in them, indicating that they are managed by a service provider.&quot; class=&quot;graf-image&quot; data-height=&quot;647&quot; data-image-id=&quot;1*XC33QK5gIuFEG5vKbjQ9fA.png&quot; data-width=&quot;1062&quot; height=&quot;390&quot; src=&quot;https://cdn-images-1.medium.com/max/1280/1*XC33QK5gIuFEG5vKbjQ9fA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;With a managed Kubernetes service, the underlying infrastructure and parts of the control plane are locked down, and kept in a read-only state for anyone outside the service provider. Your company still has access to the cluster, including many parts of the control plane, such as being able to add storage classes and daemon&amp;nbsp;sets.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;01c9&quot;&gt;The deciding factor here is the scale of deployment. Setting up CI/CD pipelines to validate new versions of clusters and skilling up an entire shift of on-call engineers (12–18 people) make no financial sense when you only need a handful of clusters. Once you reach ten or more, it &lt;em class=&quot;markup--em markup--p-em&quot;&gt;may&lt;/em&gt; be cost-effective to staff an entire Kubernetes operations team and develop that practice in-house.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d6fe&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Takeaway&lt;/strong&gt;: Managed clusters offer a different balance between cost and ownership, making even well-established Kubernetes shops &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.infoworld.com/article/3664052/why-mercedes-benz-runs-on-900-kubernetes-clusters.html&quot; href=&quot;https://www.infoworld.com/article/3664052/why-mercedes-benz-runs-on-900-kubernetes-clusters.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;consider their options&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8b03&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;3810&quot;&gt;Lesson #4 — Stateless first, serverless second&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7fc9&quot;&gt;It is tempting to analyze the workloads in a Kubernetes cluster and stare longingly at shifting everything to a container service in the same IaaS.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;bc5d&quot;&gt;Using a managed container service may be a perfect fit for stateless and short-lived workloads, such as a micro-service that translates a page of text from one language to another. Still, if you consulted with your operations team, they would probably tell you that stateful workloads are their most significant source of worry and where they spend most of their engineering efforts. These are your database and messaging clusters, with their intricate procedures for storage, backups, archiving, upgrades, and so on.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;d726&quot;&gt;&lt;img alt=&quot;Copy of the first picture with the 3 layers of a box showing containers, Kubernetes components, and then infrastructure components. The middle and bottom layers have lock signs in them, indicating that they are managed by a service provider. Some of the services are no longer in the first layer, but on a separate box, managed by a separate company (named ACME.)&quot; class=&quot;graf-image&quot; data-height=&quot;611&quot; data-image-id=&quot;1*GpobhoDECigmJUWGmKFQHw.png&quot; data-width=&quot;1014&quot; height=&quot;386&quot; src=&quot;https://cdn-images-1.medium.com/max/1280/1*GpobhoDECigmJUWGmKFQHw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Running stateful dependencies inside a cluster is significantly more complex than running stateless workloads. Things like backup, archival, disaster recovery, and upgrades require specialized skills, detailed planning, and continuous upkeep.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6711&quot;&gt;Recalling lesson #2 (“90% of nothing is nothing”,) dealing with stateless workloads first may not result in a meaningful reduction in the overall budget of the “Operations” cycle of the product, so consider dealing with stateful workloads first.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a67a&quot;&gt;Those workloads do not fit a serverless model well, as the compute aspect (CPUs) sits inside the pod, coupled with mounted storage volumes. In that case, the starting point is to replace those workloads with a service in the IaaS, such as using managed instances of PostgreSQL or Kafka.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;873f&quot;&gt;Note that such shifts still leave residual operational costs behind, such as the need to monitor the health of the service and have procedures in place to track eventual problems to failures in the service. Still, those activities require fewer people and do not require in-depth knowledge of the service runtimes.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;71d2&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Takeaway&lt;/strong&gt;: Assess how much of your overall product cost is spent on each service in your data center, from design to support. Then assess whether it could cost less (again, in terms of total cost) to lease the services from a specialized company.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;3f12&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;bef0&quot;&gt;Lesson 5 — Virtual&amp;nbsp;Kubelets&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;61a2&quot;&gt;Although not as pervasive across all cloud providers (see examples &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://azure.microsoft.com/en-us/services/container-instances&quot; href=&quot;https://azure.microsoft.com/en-us/services/container-instances&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://docs.aws.amazon.com/eks/latest/userguide/fargate-getting-started.html&quot; href=&quot;https://docs.aws.amazon.com/eks/latest/userguide/fargate-getting-started.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;,) this type of service is an excellent addition to a managed Kubernetes service. Virtual Kubelets extend the cluster scheduling service to run select containers elsewhere in the IaaS instead of inside a cluster node.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;770d&quot;&gt;That is an excellent solution for scenarios where you are not ready to rearchitect the entire system into a combination of services and still need to keep Kubernetes clusters around for a while, with the added advantage of keeping the number of fixed worker nodes as low as possible.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8bea&quot;&gt;Since the approach reuses Kubernetes development and deployment APIs, the costs of transitioning to a serverless model are minimal.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;11a5&quot;&gt;&lt;img alt=&quot;Copy of the first picture with the 3 layers of a box showing containers, Kubernetes components, and then infrastructure components. The middle and bottom layers have lock signs in them, indicating that they are managed by a service provider. Some of the services are no longer in the first layer, but on a separate box, managed by a separate company (named ACME.) Some of the containers and pods are on yet another box, also managed by ACME.&quot; class=&quot;graf-image&quot; data-height=&quot;570&quot; data-image-id=&quot;1*CSqXNAwCBZ-pG2Wf5yn6Ww.png&quot; data-width=&quot;1124&quot; height=&quot;325&quot; src=&quot;https://cdn-images-1.medium.com/max/1280/1*CSqXNAwCBZ-pG2Wf5yn6Ww.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;With a virtual kubelet, someone creates a new workload in a managed cluster. The service provider uses additional user configuration to decide whether to schedule the pod inside the cluster or elsewhere in the service provider&amp;nbsp;cloud.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8cd5&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Takeaway&lt;/strong&gt;: If you already leaped into using managed Kubernetes clusters, isolate workloads that don’t run frequently and don’t need to run inside the cluster. Let the service provider schedule those pods outside the cluster, then deallocate whatever fixed cluster capacity you had set aside for them.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;5725&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;5dab&quot;&gt;Lesson #6: Auto-scale all&amp;nbsp;things&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d9c0&quot;&gt;If you got this far, you have workloads that cannot be sensibly moved out of a Kubernetes cluster. The only thing left is eliminating wasteful capacity overprovisioning within the cluster.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;32a7&quot;&gt;For instance, if your cluster has ten worker nodes and they are all above 90% resource utilization (CPU, memory, or disk), the temporary loss of a worker node means the cluster can no longer schedule all pods.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4fef&quot;&gt;When you look closer into that utilization, the waste becomes more apparent, as you realize that a sizeable slice is allocated to container resource requests, whether or not a container requesting the resources is using them.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;dcff&quot;&gt;And remember what I mentioned about the total cost of operations? Unschedulable pods will likely cause problems in other systems and prompt several people to deal with the situation, from customers contacting support to automated monitors paging people to look into the issue.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;de75&quot;&gt;I covered auto-scaling options in &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/kubernetes-resources-1a1fa1e72dcf&quot; href=&quot;https://dnastacio.medium.com/kubernetes-resources-1a1fa1e72dcf&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;this story&lt;/a&gt;, but in a nutshell, you want to consider:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;0814&quot;&gt;HPA (Horizontal Pod Autoscaling): Adapts the number of replicas for a workload based on resource utilization in the workload containers&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;30b6&quot;&gt;VPA (vertical pod autoscaling): Modifies container sizes in scenarios where one cannot modify the number of container replicas.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f24c&quot;&gt;KPA (Knative pod autoscaling:) Schedules containers based on request-per-second targets, with the option to scale a deployment down to zero if there are no pending requests for a while.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;abb3&quot;&gt;Cluster autoscaling: Scales pools of worker nodes according to the resource requests and utilization.&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;4d0e&quot;&gt;&lt;img alt=&quot;Illustration of how pod autoscaling technologies handle containers that need more resources. The overloads containers are represented as small boxes stretched in their middle and with steam coming out of corners. HPA creates another box of same size, but not overstretched anymore. VPA makes the box larger. KPA creates more boxes, then deletes them after the work is done.&quot; class=&quot;graf-image&quot; data-height=&quot;790&quot; data-image-id=&quot;1*KsT7iq4uWX__LpI_FHN9aA.png&quot; data-width=&quot;1909&quot; height=&quot;265&quot; src=&quot;https://cdn-images-1.medium.com/max/1280/1*KsT7iq4uWX__LpI_FHN9aA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Pod autoscaling technology automatically adjusts capacity to match workloads. When paired with cluster-autoscaling, they allow the operations team to run containers with fewer nodes. The effects are more noticeable on the IaaS bill as a marginal change in the number of cluster nodes has little impact on the effort required to manage the&amp;nbsp;cluster.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c5a2&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Takeaway&lt;/strong&gt;: Autoscaling is not for everyone; it takes work to get right. It is an option for large-scale deployments where the savings in runtime costs offset the investment in deploying and tuning the autoscalers.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;7b39&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;47b9&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f0ae&quot;&gt;Kubernetes is a noticeable portion of an IT infrastructure, and optimizing resource utilization may be a tempting starting point for cost reductions.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ca06&quot;&gt;Please resist the temptation to start at the most visible target and take the time to understand the total cost of operations for a product and its distribution across the multiple stages of the product lifecycle.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;48c6&quot;&gt;Teams with design and development responsibilities must grasp how other stages work and make every decision with the overall cost to the project in mind.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2513&quot;&gt;Shifting entire system layers to IaaS vendors can be a sensible choice for small operations teams, where it may not be possible to staff 24x7 on-call shifts of people skilled across all layers of the stack. Adopting managed Kubernetes over self-hosted clusters is a good starting point, while stateful workloads make for an excellent second step.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;5b8d&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/1192508289884721711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/06/are-you-spending-too-much-on-kubernetes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/1192508289884721711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/1192508289884721711'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/06/are-you-spending-too-much-on-kubernetes.html' title='Are you spending too much on Kubernetes?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Raleigh, NC, USA</georss:featurename><georss:point>35.7795897 -78.6381787</georss:point><georss:box>8.2713122045790826 -113.7944287 63.287867195420922 -43.4819287</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-574723374341414623</id><published>2022-05-24T14:36:00.007-07:00</published><updated>2022-05-28T12:04:32.989-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="argo"/><category scheme="http://www.blogger.com/atom/ns#" term="flux"/><category scheme="http://www.blogger.com/atom/ns#" term="gitops"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="terraform"/><title type='text'>GitOps repos: Five lessons on what to include and what to skip</title><content type='html'>&lt;p&gt;&lt;i&gt;(I originally posted this article on&amp;nbsp;&lt;a href=&quot;https://dnastacio.medium.com/gitops-repo-content-a31884d4104f&quot; target=&quot;_blank&quot;&gt;medium.com&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/i&gt;&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;5b8d&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fa2c&quot;&gt;This article provides a decision framework to help practitioners choose &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;what to manage with GitOps and what to avoid.&lt;/strong&gt; It is a companion to my previous article on &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5?source=friends_link&amp;amp;sk=f388bc2a35c58be1abcd6bd898bb65bf&quot; href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5?source=friends_link&amp;amp;sk=f388bc2a35c58be1abcd6bd898bb65bf&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;structuring GitOps repositories&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b403&quot;&gt;With the advent of &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://en.wikipedia.org/wiki/Infrastructure_as_code&quot; href=&quot;https://en.wikipedia.org/wiki/Infrastructure_as_code&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Infrastructure as Code (IaC)&lt;/a&gt; frameworks like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://en.wikipedia.org/wiki/Terraform_(software)&quot; href=&quot;https://en.wikipedia.org/wiki/Terraform_%28software%29&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Terraform&lt;/strong&gt;&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.pulumi.com/docs/intro/vs/terraform/&quot; href=&quot;https://www.pulumi.com/docs/intro/vs/terraform/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Pulumi&lt;/strong&gt;&lt;/a&gt; and their ability to build entire environments from nothing but a well-funded cloud account, the scope of what you can manage with IaC-based approaches has virtually no limits.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d93b&quot;&gt;Even companies running on-premise hardware can benefit from an extensive library of plugins listed in the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://registry.terraform.io/&quot; href=&quot;https://registry.terraform.io/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Terraform&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.pulumi.com/registry/&quot; href=&quot;https://www.pulumi.com/registry/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Pulumi registries&lt;/a&gt;. And if a plugin is not available, people can author new plugins using languages and toolkits like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.terraform.io/language&quot; href=&quot;https://www.terraform.io/language&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;HCL&lt;/a&gt;, &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.pulumi.com/docs/reference/pulumi-sdk/&quot; href=&quot;https://www.pulumi.com/docs/reference/pulumi-sdk/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Pulumi’s SDK&lt;/a&gt;, and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.terraform.io/cdktf&quot; href=&quot;https://www.terraform.io/cdktf&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Terraform’s CDK&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d4a1&quot;&gt;Without technology barriers, it is easy to start bringing everything into GitOps repositories and wonder whether some of that data may be better managed elsewhere.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e56c&quot;&gt;I learned the lessons in the following sections the harder way while establishing our practices. I hope they can help make your decisions a little easier.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;6f53&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;6ebc&quot;&gt;Lesson #1: Configuration formats&amp;nbsp;matter&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5c8b&quot;&gt;Part of the decision about which configuration to manage with GitOps is the choice of the IaC framework, which should prioritize alignment with the system abstractions.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7053&quot;&gt;As an example, I mentioned Terraform in the introduction. Its &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/hashicorp/hcl#information-model-and-syntax&quot; href=&quot;https://github.com/hashicorp/hcl#information-model-and-syntax&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;data structures and syntax&lt;/a&gt; are good at mapping IaaS resources such as VPCs, VMs, and network gateways. As you move up the complexity ladder, they may not be adequate to describe the internal configuration of other components, such as Kubernetes clusters.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5e24&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/guides/getting-started&quot; href=&quot;https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/guides/getting-started&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Terraform’s Kubernetes provider&lt;/a&gt; can do the job, but the extra layer of abstraction used to represent cluster configuration makes it a challenging medium for anything beyond a couple of resources.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fe2e&quot;&gt;Once the number of configuration objects increases, I recommend incorporating domain-specific frameworks like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argoproj.github.io/cd/&quot; href=&quot;https://argoproj.github.io/cd/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Argo CD&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://fluxcd.io/&quot; href=&quot;https://fluxcd.io/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Flux&lt;/a&gt; into the IaC mix. Those frameworks allow cluster administrators to work with GitOps repositories containing Kubernetes resource definitions.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;ea12&quot;&gt;&lt;img alt=&quot;Two-part picture. Left side has a repo administrator staring at a circle representing the entire system. The circle contains a directed graph with circles and squares containing single alphabet letters. Right-side of picture has a tree-like structure of folders, containing two parent folders (VMs and clusters,) each containing a few alphabet letters mapping to the letters in the left-side of the picture. Robots labeled “Terraform” and “Argo” look at the “VMs” and “clusters” folders, respectively&quot; class=&quot;graf-image&quot; data-height=&quot;512&quot; data-image-id=&quot;1*kvnWgEUeYjnONBkktvI_KQ.png&quot; data-is-featured=&quot;true&quot; data-width=&quot;1314&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*kvnWgEUeYjnONBkktvI_KQ.png&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;It may be impractical to use a single IaC framework in a large environment due to the specialized needs of complex components. For instance, Terraform excels at allocating resources at the IaaS level, while Argo CD excels at managing Kubernetes configuration.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2d99&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Takeaway:&lt;/strong&gt; As the system grows and your IaC starts demanding awkward mappings for new configuration formats, consider incorporating new frameworks that match the way people work.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;30fa&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;c3be&quot;&gt;Lesson #2: Favor behavior before&amp;nbsp;state&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ab2e&quot;&gt;Modern infrastructure can be mind-bogglingly extensive, making the complete representation of their desired state virtually impossible. We often need to settle for things that &lt;em class=&quot;markup--em markup--p-em&quot;&gt;act the same&lt;/em&gt; instead of obsessing over making them &lt;em class=&quot;markup--em markup--p-em&quot;&gt;precisely the same&lt;/em&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5142&quot;&gt;For instance, assume a VM running Ubuntu. Only a couple of its configuration files may require modification post-installation for the VM to perform its role in the system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;387e&quot;&gt;In that scenario, it is more reasonable to represent the differences between the VM’s desired configuration and their default values in the image template. To make the picture worse, and for a bit of real-world GitOps heresy, a few configuration files may be opaque boxes requiring imperative approaches like Terraform’s &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.terraform.io/language/resources/provisioners/remote-exec&quot; href=&quot;https://www.terraform.io/language/resources/provisioners/remote-exec&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;remote-exec&lt;/a&gt; or &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.ansible.com/&quot; href=&quot;https://www.ansible.com/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Ansible&lt;/a&gt; to complete the job.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c01e&quot;&gt;Take that example further and assume your production system depends on a managed Kubernetes offering like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://aws.amazon.com/rosa/&quot; href=&quot;https://aws.amazon.com/rosa/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;ROSA&lt;/a&gt;. Your GitOps repository may specify it needs one of such clusters, and a Terraform plugin will be happy to oblige. However, ROSA’s SRE team retains control of many low-level resources underpinning the cluster, such as VMs, disks, and networking.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;674c&quot;&gt;&lt;img alt=&quot;Folder structure with “VMs” and “clusters” at the first level. The “VMs” folder has a highlighted “G” folder with a callout showing its definition being “Ubunty 16.04” plus changes to files in “/etc/hosts” plus an invocation of Terraform’s “remote-exec” primitive.&quot; class=&quot;graf-image&quot; data-height=&quot;620&quot; data-image-id=&quot;1*QhlVL7yxhGKW4np1i5vUqA.png&quot; data-width=&quot;1270&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*QhlVL7yxhGKW4np1i5vUqA.png&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;GitOps principles call for declarative and immutable settings. Still, sometimes you need to bend those principles and store configuration relative to baselines that may be entirely or partially outside your&amp;nbsp;control.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;35f6&quot;&gt;In short, we must grudgingly accept that we are often &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;aiming for similar behavior rather than for the desired state&lt;/strong&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;eff0&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;b768&quot;&gt;Lesson #3: Leave out state co-managed by specialized components&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1c2f&quot;&gt;The first type of “state” matching this lesson is application data. It is managed inside specialized servers with their own APIs and tooling. Now, let’s broaden the concept from “application data” to &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“data that has its dedicated system of record, lifecycle, and workflow.”&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7867&quot;&gt;The distinction is helpful because sometimes, you may need to share configuration management with other components outside the GitOps framework.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0449&quot;&gt;Some of the best examples of co-management are the various fields used to control the number of replicas for pods and worker nodes in an &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/kubernetes-resources-1a1fa1e72dcf?source=friends_link&amp;amp;sk=0ae9728422d149d00e0761f438bbd019&quot; href=&quot;https://dnastacio.medium.com/kubernetes-resources-1a1fa1e72dcf?source=friends_link&amp;amp;sk=0ae9728422d149d00e0761f438bbd019&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;autoscaled environment&lt;/a&gt;. In those situations, you want most of the workload definition in the GitOps repository while deferring things like replica counts and resource limits to autoscaling components in the cluster. Note you still want the configuration for the autoscaling components managed with GitOps.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;a38e&quot;&gt;&lt;img alt=&quot;A circle represents the whole environment, containing a directed graph. This is the same circle depicted atop the article, but now the smaller circle labeled “F” is at the edge of the larger circle, and a robot inspects the configuration for the smaller circle and then sets the number of “replicas” of the circle to “5”. An admin responsible for the whole environment watches the robot and allows it  to proceed.&quot; class=&quot;graf-image&quot; data-height=&quot;486&quot; data-image-id=&quot;1*SWG-ox0U2-FX-vbgyGDFug.png&quot; data-width=&quot;980&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*SWG-ox0U2-FX-vbgyGDFug.png&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Automated processes and components may be better positioned to configure or tune details of some aspects of the infrastructure.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ba2d&quot;&gt;Kubernetes addresses that overlap with the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/using-api/server-side-apply/&quot; href=&quot;https://kubernetes.io/docs/reference/using-api/server-side-apply/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“server-side apply”&lt;/a&gt; pattern, allowing different components to manage (or co-manage) certain portions of a resource. &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/diffing/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/diffing/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Argo CD supports that pattern through resource annotations&lt;/a&gt;, telling it to ignore entire branches of a resource or &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/using-api/server-side-apply/#field-management&quot; href=&quot;https://kubernetes.io/docs/reference/using-api/server-side-apply/#field-management&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;specific managed fields&lt;/a&gt; during drift detection.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;3ead&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;b6a6&quot;&gt;Lesson #4: Avoid secrets and certificates&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4aa2&quot;&gt;We often see articles and tutorials extolling the virtues of storing encrypted secrets inside Git repositories, a technique commonly known as “sealed secrets.” Since secrets (and certificates) have their own system of record, lifecycle, and workflows, the previous lesson of avoiding that kind of data in a Git repository still applies.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;807c&quot;&gt;If you need extra convincing, I wrote an extended version of my reasons for &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/why-you-should-avoid-sealed-secrets-in-your-gitops-deployment-e50131d360dd?source=friends_link&amp;amp;sk=ccfe406e91e3b03c3893bc492082f1c3&quot; href=&quot;https://dnastacio.medium.com/why-you-should-avoid-sealed-secrets-in-your-gitops-deployment-e50131d360dd?source=friends_link&amp;amp;sk=ccfe406e91e3b03c3893bc492082f1c3&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;not recommending the practice of using sealed secrets with GitOps&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;56f3&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;8f71&quot;&gt;Lesson #5: Treat the &lt;a class=&quot;markup--anchor markup--h4-anchor&quot; data-href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d&quot; href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitOps CI/CD pipeline&lt;/a&gt; as code&amp;nbsp;too&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e5d8&quot;&gt;I earlier wrote about how it is possible to bring the desired state of the entire system into Git repositories. This section extends the definition of “system” to the GitOps repositories and pipelines underpinning those deployments.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ea67&quot;&gt;I know this may sound overly abstract, but the increased consistency leads to more productivity and better security.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;91a5&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.cloudbees.com/blog/pipeline-as-code-simple-explanation-with-examples&quot; href=&quot;https://www.cloudbees.com/blog/pipeline-as-code-simple-explanation-with-examples&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Pipeline as Code&lt;/a&gt; technologies such as &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argoproj.github.io/argo-workflows/&quot; href=&quot;https://argoproj.github.io/argo-workflows/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Argo Workflows&lt;/a&gt;, &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://tekton.dev/&quot; href=&quot;https://tekton.dev/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Tekton&lt;/a&gt;, and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/features/actions&quot; href=&quot;https://github.com/features/actions&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitHub Actions&lt;/a&gt; are good choices for applying GitOps principles to pipelines.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;40b3&quot;&gt;I particularly like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://faun.pub/how-to-configure-github-environments-with-terraform-d2b76766547b&quot; href=&quot;https://faun.pub/how-to-configure-github-environments-with-terraform-d2b76766547b&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;this article&lt;/a&gt; from Alexandre Couëdelo showing how one can use Terraform to configure the very Git repositories holding the infrastructure definitions. That kind of approach ensures remote repositories remain configured correctly without risking loopholes that could compromise the entire CI/CD pipeline.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;a1be&quot;&gt;&lt;img alt=&quot;The entire overview picture at the beginning of the article is depicted inside a larger circle, representing the whole system. On the right side of the entire picture has a robot tending to a tree structure containing top-level folders for pipeline-as-code technologies, such as Argo and Tekton. These folders contain the pipeline definitions for the GitOps folders.&quot; class=&quot;graf-image&quot; data-height=&quot;870&quot; data-image-id=&quot;1*2vXFLXZsqtOGqczoKclbJA.png&quot; data-width=&quot;1786&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*2vXFLXZsqtOGqczoKclbJA.png&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;GitOps can also manage the artifacts behind the primary GitOps process, supporting versioned and consistent settings for CI/CD pipelines.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;187b&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;24ae&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5a6e&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Define the boundaries of your entire system &lt;/strong&gt;early on and decide on a phased approach to bring configuration into &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;one or more GitOps repositories&lt;/a&gt;. Some components will be whole &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;systems within the system&lt;/strong&gt;, requiring multiple GitOps frameworks to cover everything.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d40d&quot;&gt;The internal state of some components may be too extensive and dynamic for the complete representation in a Git repository, requiring &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;adaptation of &lt;/strong&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://opengitops.dev/&quot; href=&quot;https://opengitops.dev/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;GitOps principles&lt;/strong&gt;&lt;/a&gt;. Accept you will often be aiming at &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;system behavior rather than system state&lt;/strong&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8a8a&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Do not store any data already managed in a specialized system of record&lt;/strong&gt;, such as application data and secrets. Watch for resources co-managed using a server-side apply pattern, then &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;configure your GitOps framework to ignore co-managed fields during drift detection&lt;/strong&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e43a&quot;&gt;And lastly, &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;use GitOps to manage GitOps&lt;/strong&gt;, adopting Pipeline as Code approaches that extend the benefits of GitOps to your &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d&quot; href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitOps CI/CD pipelines&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/574723374341414623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/05/gitops-repos-five-lessons-on-what-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/574723374341414623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/574723374341414623'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/05/gitops-repos-five-lessons-on-what-to.html' title='GitOps repos: Five lessons on what to include and what to skip'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Raleigh, NC, USA</georss:featurename><georss:point>35.7795897 -78.6381787</georss:point><georss:box>7.469355863821157 -113.7944287 64.089823536178841 -43.4819287</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-5249933657098121250</id><published>2022-05-10T15:01:00.002-07:00</published><updated>2022-05-12T05:21:00.680-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="autoscaling"/><category scheme="http://www.blogger.com/atom/ns#" term="containers"/><category scheme="http://www.blogger.com/atom/ns#" term="hpa"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="vpa"/><title type='text'>Infinite scaling with containers and Kubernetes: The total perspective vortex</title><content type='html'>&lt;p&gt;&lt;i&gt;&amp;nbsp;(I originally posted this article on&amp;nbsp;&lt;a href=&quot;https://dnastacio.medium.com/kubernetes-resources-1a1fa1e72dcf?source=friends_link&amp;amp;sk=0ae9728422d149d00e0761f438bbd019&quot; target=&quot;_blank&quot;&gt;medium.com&lt;/a&gt;)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;0f05&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;cb92&quot;&gt;Containerizing the best code in the world means nothing if that container does not have the resources to do its job.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7933&quot;&gt;The idea for this story started while &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://sourcepatch.blogspot.com/search/label/container-probes&quot; href=&quot;https://sourcepatch.blogspot.com/search/label/container-probes&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;writing about effective container probes&lt;/a&gt;. It became clear that giving precise answers about readiness and liveness to the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/&quot; href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;kubelet&lt;/a&gt; was only the first part of the problem.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d8b3&quot;&gt;The second part is the subject of this article: &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;allocating resources to containers.&lt;/strong&gt; Containers started with insufficient resources perform poorly and, in extreme cases, risk termination due to successive timeouts in their liveness probe. On the other hand, containers started with unnecessary resources are one of the fastest ways of converting your budget into heat.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;41ff&quot;&gt;This article draws a cloud landscape of resource allocation, from a single container in a Kubernetes pod to near-infinite capacity in the cloud, so it is time to buckle up!&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;6a80&quot;&gt;&lt;img alt=&quot;Dot in a vastness of space is called out into what looks yet another expanse of a galaxy, from where yet another dot is expanded, revealing a system administrator grappling with resources in a Kubernetes cluster.&quot; class=&quot;graf-image&quot; data-height=&quot;380&quot; data-image-id=&quot;1*WU3YIrmoFIzg9w5QdOFoBg.png&quot; data-width=&quot;695&quot; height=&quot;350&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*WU3YIrmoFIzg9w5QdOFoBg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;The scaling of container-based workloads evolved rapidly in the past few years, making concerns about resource capacity a thing of the past in system&amp;nbsp;design.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;d255&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;43b7&quot;&gt;Kubernetes resource management: a&amp;nbsp;recap&lt;/h3&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;03e3&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“How to ensure containers always have the resources they need?”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0fa8&quot;&gt;Consider this section a recap for those just starting with Kubernetes resource management. The official documentation on &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/&quot; href=&quot;https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Kubernetes resource management for containers&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/policy/limit-range/&quot; href=&quot;https://kubernetes.io/docs/concepts/policy/limit-range/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;namespace limit ranges&lt;/a&gt; is still mandatory reading in the space. If you are already familiar with the subject, skip to the next section.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2319&quot;&gt;Kubernetes resource management primarily covers &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;CPU, memory&lt;/strong&gt;, and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage&quot; href=&quot;https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;local ephemeral storage&lt;/strong&gt;&lt;/a&gt;. A container specification may define &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources&quot; href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;resource requests and resource limits&lt;/a&gt; for each resource type.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7591&quot;&gt;A &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;resource request&lt;/strong&gt; is the minimum amount of that resource required for the container runtime. The node scheduler only schedules a pod to a worker node if that node can meet the resource requests from all containers in the pod.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;33d0&quot;&gt;A &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;resource limit&lt;/strong&gt; is the maximum amount of resources the kubelet should allocate to a container during its lifetime. When a container has the resource limit set and lacks the resource request declaration, the latter is presumed to be identical to the resource limit.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;b7d5&quot;&gt;&lt;img alt=&quot;Developers staring at a container and guessing which limits to set for CPU and memory, then realizing that is only one out of many containers in a pod.&quot; class=&quot;graf-image&quot; data-height=&quot;545&quot; data-image-id=&quot;1*RwRKe5RnOTZKLDWwGCZMSA.png&quot; data-width=&quot;932&quot; height=&quot;374&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*RwRKe5RnOTZKLDWwGCZMSA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Kubernetes allows software developers and system administrators to collaborate on setting minimum reservations and maximum limits for resources like CPU, memory, and temporary storage.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;bc88&quot;&gt;A container may have any combination of resource requests and limits, with the different combinations of CPU and memory reservation defining the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod&quot; href=&quot;https://kubernetes.io/docs/tasks/configure-pod-container/quality-service-pod&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;quality of service&lt;/a&gt; for the parent pod as follows:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;e86d&quot;&gt;Every container in the pod has both resource request and limit set, and for each container, request and limit have the same value: &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Guaranteed.&lt;/strong&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;8b70&quot;&gt;Resource requests or limits not set for any container in the pod: &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;BestEffort.&lt;/strong&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;6aa6&quot;&gt;All other pods that are not in the two previous buckets: &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Burstable.&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure graf--startsWithDoubleQuote&quot; name=&quot;b96b&quot;&gt;&lt;img alt=&quot;Box on the left representing a container, with watermark at the bottom indicating resource requests and a dashed line closer to the top, indicating container limits. Three circles representing pods with containers inside them. One circle represents “Guaranteed” workloads, another representing “Burstable” workloads, and the last one representing “BestEffort” pods.&quot; class=&quot;graf-image&quot; data-height=&quot;844&quot; data-image-id=&quot;1*2YilxjkuwdCi0ps3xLU1gw.png&quot; data-width=&quot;1648&quot; height=&quot;328&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*2YilxjkuwdCi0ps3xLU1gw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;“Guaranteed” workloads have the same value for limits and requests for both CPU and memory in all containers. Requests are guaranteed to be honored if all “Guaranteed” workloads fit in the cluster. Anything above “requests” and below “limits” depends on the cluster having spare resources. “BestEffort” containers are the first to be evicted if the cluster runs out of resources.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;92b7&quot;&gt;It is helpful to look at what these categories mean when the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/&quot; href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;kube-scheduler&lt;/a&gt; decides to schedule a pod on a worker node:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li graf--startsWithDoubleQuote&quot; name=&quot;3350&quot;&gt;“Guaranteed” means the scheduler only assigns the pod to worker nodes with enough resources to meet the pod request.&lt;/li&gt;&lt;li class=&quot;graf graf--li graf--startsWithDoubleQuote&quot; name=&quot;8958&quot;&gt;“Burstable” QoS means the scheduler looks for a worker node with enough memory to meet the resource requests of the pod. &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;The scheduler does not care whether the worker node can meet the resource limits of containers in the pod&lt;/strong&gt; or anything above the resource request, for that matter.&lt;/li&gt;&lt;li class=&quot;graf graf--li graf--startsWithDoubleQuote&quot; name=&quot;78ca&quot;&gt;“BestEffort” means the scheduler will meet the resource requests of every pod with a Guaranteed or Burstable QoS before scheduling the pod. The scheduler continuously revisits that assessment, so &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;it may still mark a BestEffort pod for eviction&lt;/strong&gt; if a “Guaranteed” or “Burstable” pod needs those same resources.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;2160&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;3a4d&quot;&gt;&lt;strong class=&quot;markup--strong markup--h3-strong&quot;&gt;Decision time&lt;/strong&gt;: Who should define container resources?&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0f01&quot;&gt;The decision on requests and limits starts with understanding that &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;resource requests protect the container &lt;/strong&gt;while&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt; resource limits protect the cluster&lt;/strong&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ccdc&quot;&gt;The two main parties in that decision are &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;product developers&lt;/strong&gt; and &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;system administrators&lt;/strong&gt;. The challenge is spread over time, as product developers spend most of the time establishing resource boundaries in isolation from deployment to production environments.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;963a&quot;&gt;On the flip side, &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;system administrators&lt;/strong&gt; often find themselves dealing with &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/workloads/&quot; href=&quot;https://kubernetes.io/docs/concepts/workloads/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Kubernetes workload&lt;/a&gt; specifications with insufficient documentation on how changes in preset requests and limits affect the workloads.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6ac1&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Product developers&lt;/strong&gt; have greater visibility into the needs of the workloads and their behavior under different resource allocations. In general, they should be able to identify at least the following thresholds during the months where they labored over the code base ahead of shipment:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;79cb&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Absolute minimum &lt;/strong&gt;resource request. This value is the resource utilization required to load the runtime and be able to answer probe requests from the kubelet comfortably. &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://sourcepatch.blogspot.com/2022/01/kubernetes-probes-part-3-promql.html&quot; href=&quot;https://sourcepatch.blogspot.com/2022/01/kubernetes-probes-part-3-promql.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;This article shows several PromQL queries&lt;/a&gt; to identify troubled containers.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;23ff&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Maximum usable&lt;/strong&gt; resource limit. This value is the point where the performance of the container starts to hit external limitations, such as disk I/O or bottlenecks in calls to 3rd party services.&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;45f9&quot;&gt;&lt;img alt=&quot;Container box with 4 marking resource limits, from top to bottom: resource limit, maximum usable resources, resource request, absolute minimum. Anything above the limit is marked as “waste”, anything between absolute minimum and resource request is marked “safety”.&quot; class=&quot;graf-image&quot; data-height=&quot;426&quot; data-image-id=&quot;1*eNwLM9YBKcsCHX8yVa9brQ.png&quot; data-is-featured=&quot;true&quot; data-width=&quot;740&quot; height=&quot;368&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*eNwLM9YBKcsCHX8yVa9brQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Product developers must define the range of absolute minimum and maximum usable resources, then balance runtime safety and resource waste when choosing resource requests and&amp;nbsp;limits.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8378&quot;&gt;Ideally, product developers should also establish and document how the container performance varies within those boundaries. That information enables system architects to plan initial capacity before deployment and system administrators to adjust resource requests in production environments.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;e469&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;1f22&quot;&gt;Quotas and range: Avoiding the tragedy of the&amp;nbsp;commons&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a002&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;System administrators&lt;/strong&gt; have visibility into cluster capacity and how much of that capacity is still available. As someone who often wears an SRE hat, I appreciate workloads in the “Guaranteed” QoS bucket. It takes a special kind of confidence (and lots of testing) for a development organization to set fixed resource boundaries on all containers in a pod and trust that pod to work reliably within those boundaries.&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;e602&quot;&gt;“Burstable” workloads fall somewhat lower in that spectrum of trust. As an SRE, my best hope is that all containers in a burstable pod have those “absolute minimum” resource requests mentioned in the previous section.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3ba3&quot;&gt;When it comes to resource limits in a burstable workload, my opinion depends on the development philosophy behind those limits:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;cc86&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;(good) Autoscaling within the workload&lt;/strong&gt; (such as a Java Virtual Machine launched with minimum and maximum memory limits.) This kind of arrangement (resource limit set higher than resource request) means the development team spent time identifying the usable operational range of the workload and has a good grip on managing those resources.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;23b7&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;(bad) Protection against eventual bugs&lt;/strong&gt;. This design philosophy reminds me of the “&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.investopedia.com/terms/t/tragedy-of-the-commons.asp&quot; href=&quot;https://www.investopedia.com/terms/t/tragedy-of-the-commons.asp&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;tragedy of the commons&lt;/a&gt;,” where everyone takes a bit more of a shared resource to anticipate its eventual exhaustion, accelerating the exhaustion of the shared resource. That philosophy is particularly disastrous when the development team underestimates the resource requests. In that situation, the workload continuously operates in the burstable zone of its operational range, making it susceptible to CPU throttling, memory exhaustion, and termination by the kubelet in the worker node.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a683&quot;&gt;And that finally leaves us with “BestEffort” workloads, a perennial source of worries due to their unfettered ability to exhaust cluster resources and their tenuous scheduling status in the face of other pods requesting those same resources.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8562&quot;&gt;When dealing with these types of workloads, a system administrator must take a moment to consider their options:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;ebb3&quot;&gt;Use &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/policy/limit-range/&quot; href=&quot;https://kubernetes.io/docs/concepts/policy/limit-range/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;limit ranges&lt;/strong&gt;&lt;/a&gt; to set default resource requests and limits for containers and pods in a namespace. I think the blanket assignment of identical resource limits for all workloads combined with the lack of input from the product developers makes it an unrealistic proposition.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f8e9&quot;&gt;Use &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/policy/resource-quotas/&quot; href=&quot;https://kubernetes.io/docs/concepts/policy/resource-quotas/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;resource quotas&lt;/strong&gt;&lt;/a&gt; to cap the combined resources for all pods in a namespace. This approach is a more promising solution. It reduces the blast radius of an eventual container going haywire without the waste of multiplying the safety buffer by the number of pods in the namespace.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;cec4&quot;&gt;Take a deep breath and hope for relief from the &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;pod autoscaling&lt;/strong&gt; technologies covered in the next section.&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;2922&quot;&gt;&lt;img alt=&quot;System administrator tightening a clamp around a Kubernetes cluster, representing the application of resource quotas and limit ranges.&quot; class=&quot;graf-image&quot; data-height=&quot;496&quot; data-image-id=&quot;1*-L_pAtWNRJJncNpSUUie0Q.png&quot; data-width=&quot;918&quot; height=&quot;346&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*-L_pAtWNRJJncNpSUUie0Q.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;System administrators can use resource quotas and limit ranges to keep workloads from interfering but often lack information to balance runtime safety and&amp;nbsp;waste.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;c37e&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;db34&quot;&gt;Pod autoscaling: Beyond static&amp;nbsp;sizing&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;095a&quot;&gt;Many readers are probably ready to bring up the usual workarounds for dealing with unruly workloads:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;4c23&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/&quot; href=&quot;https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Horizontal pod autoscaling (HPA)&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;34ae&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler&quot; href=&quot;https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Vertical pod autoscaling (VPA)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;053b&quot;&gt;These popular autoscaling techniques can dynamically allocate capacity within a cluster based on resource metrics; HPA can alter the number of pod replicas in a deployment, while VPA can change the resource requests and limits for a pod.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0115&quot;&gt;While capable of automatically extending capacity, these components are not a free pass to forego the precise definition of the operational ranges for their workloads. For instance, HPA will not take action on a metric where containers in the pod do not have the resource request for that metric. HPA is also ill-suited to scenarios where a deployment relies on a specific number of replicas for the pod in the cluster.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;d483&quot;&gt;&lt;img class=&quot;graf-image&quot; data-height=&quot;424&quot; data-image-id=&quot;1*HBL1xcF8lCJnGCf7YA1yzw.png&quot; data-width=&quot;892&quot; height=&quot;304&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*HBL1xcF8lCJnGCf7YA1yzw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;HPA balances deployment capacity by increasing or decreasing the number of pod replicas when the resource utilization strays from the desired target&amp;nbsp;value.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;da15&quot;&gt;Turning to VPA is better for workloads that require a fixed number of replicas or where the workload does not ship with preset limits. There is, however, a relatively long &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#known-limitations&quot; href=&quot;https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#known-limitations&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;list of limitations&lt;/a&gt;. Additionally, if using &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/policy/limit-range/&quot; href=&quot;https://kubernetes.io/docs/concepts/policy/limit-range/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;limit ranges&lt;/a&gt;, &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#limits-control&quot; href=&quot;https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#limits-control&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;the considerations&lt;/a&gt; may get quite involved.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;6a1c&quot;&gt;&lt;img class=&quot;graf-image&quot; data-height=&quot;412&quot; data-image-id=&quot;1*BHqi35ACdcS3HXxhZjshmg.png&quot; data-width=&quot;764&quot; height=&quot;345&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*BHqi35ACdcS3HXxhZjshmg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;VPA balances deployment capacity by observing resource utilization inside the pod and recreating the pod with more adequate resource requests and limits for the containers inside the pod (resizing pods without a restart is currently an experimental feature.)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5533&quot;&gt;Ultimately, the effectiveness of these tools in autoscaling workloads depends on the profiling effort spent on defining resource requests and limits during development. Here, I must give VPA extra credit for its ability to “learn” the operational resource ranges for a deployment.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;2cae&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;94eb&quot;&gt;Auto Pilot operators: SRE in a&amp;nbsp;box?&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;13b8&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/extend-kubernetes/operator/&quot; href=&quot;https://kubernetes.io/docs/concepts/extend-kubernetes/operator/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Kubernetes operators&lt;/a&gt; introduce the notion of custom resources to manage applications and workloads. Conceptually, an operator continuously watches the custom resource and maps it to &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/workloads/&quot; href=&quot;https://kubernetes.io/docs/concepts/workloads/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;workload resources&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1e14&quot;&gt;The &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://sdk.operatorframework.io/docs/overview/operator-capabilities/&quot; href=&quot;https://sdk.operatorframework.io/docs/overview/operator-capabilities/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Operator Maturity Model&lt;/a&gt; calls for five different levels of autonomy, with the highest being level 5, or “Auto Pilot.” An operator at that stage of maturity should, amongst other kinds of autonomous behavior, apply horizontal or vertical scaling to the workloads it manages.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;cc38&quot;&gt;&lt;img alt=&quot;5 boxes for 5 capability maturity models, from the left: Install, upgrades, lifecycle management and backups, insights, and auto pilot.&quot; class=&quot;graf-image&quot; data-height=&quot;331&quot; data-image-id=&quot;1*ph0YSJf4-6kWRr0eNbI7aQ.png&quot; data-width=&quot;900&quot; height=&quot;235&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*ph0YSJf4-6kWRr0eNbI7aQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Operator Maturity Model calls for “Level 5” operators capable of self-tuning and autoscaling workloads.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;178a&quot;&gt;There is an extra natural cost in developing an operator, including designing and documenting a custom resource definition. There is also the additional runtime cost of the operator pod. That is why I think the value of operators starts with level 4, or “Deep Insights,” which entails creation metrics, alerts, log processing, and workload analysis.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8983&quot;&gt;Below level 4, operators do little to alleviate the continuous cycle of product developers attempting to predict the future and system administrators trying to bend those predictions into reality.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;ee21&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;8706&quot;&gt;Knative: Elastic capacity with zero&amp;nbsp;waste&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fc41&quot;&gt;According to its website, &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://knative.dev/docs/&quot; href=&quot;https://knative.dev/docs/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Knative&lt;/a&gt; &lt;em class=&quot;markup--em markup--p-em&quot;&gt;“is an Open-Source Enterprise-level solution to build Serverless and Event-Driven Applications.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1bb4&quot;&gt;From the perspective of this article, we are interested in Knative’s &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://knative.dev/docs/serving/&quot; href=&quot;https://knative.dev/docs/serving/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Serving&lt;/a&gt; module. That module contains the Knative Pod Autoscaler (KPA,) which mimics HPA’s ability to vary the number of pod replicas to meet demand, with two key distinctions:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;07ef&quot;&gt;Scale replicas based on the volume of external requests&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;7bd1&quot;&gt;Scale replicas down to zero when there are no external requests&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;bda0&quot;&gt;&lt;img class=&quot;graf-image&quot; data-height=&quot;524&quot; data-image-id=&quot;1*2MQm2H2wtWv4P_oCqAJ-Hg.png&quot; data-width=&quot;1016&quot; height=&quot;330&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*2MQm2H2wtWv4P_oCqAJ-Hg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Knative Pod Autoscaler monitors requests to a URL and decides how many pods are required to handle the pending queue of requests. With the proper configuration and no outstanding requests, KPA removes all replicas of the pods for maximum resource&amp;nbsp;savings.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b563&quot;&gt;Unlike HPA, which reacts to resource utilization when it crosses preset boundaries, KPA makes its decisions based on &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://knative.dev/docs/serving/autoscaling/concurrency/&quot; href=&quot;https://knative.dev/docs/serving/autoscaling/concurrency/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;concurrency&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://knative.dev/docs/serving/autoscaling/rps-target/&quot; href=&quot;https://knative.dev/docs/serving/autoscaling/rps-target/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;requests-per-second&lt;/a&gt; targets.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1893&quot;&gt;As a rule-of-thumb, HPA is better suited for long-running, slow-starting processes where resource demands do not change abruptly. In contrast, KPA favors transient processes that can boot quickly to meet immediate demand.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1e35&quot;&gt;And last but not least, serverless or not, KPA works with containers, so &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://knative.dev/docs/serving/services/configure-requests-limits-services/#additional-resources&quot; href=&quot;https://knative.dev/docs/serving/services/configure-requests-limits-services/#additional-resources&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;resource limits still matter&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8640&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;572a&quot;&gt;Cluster autoscaling: Pushing the&amp;nbsp;limits&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;de48&quot;&gt;Once you have appropriately tuned all workload resources and pod autoscalers, it is time to look deeper into the toolbox and reach for the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/kubernetes/autoscaler&quot; href=&quot;https://github.com/kubernetes/autoscaler&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Kubernetes cluster autoscaler&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9083&quot;&gt;The cluster autoscaler can add (or remove) worker nodes based on resource demands. The autoscaler respects configurable lower and upper boundaries to ensure minimum capacity and some level of cost controls to avoid unruly workloads overstretching the cluster.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4d7b&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Slow stretching. &lt;/strong&gt;Remember that response times for a cluster autoscaler are decidedly sluggish compared to pod autoscalers, with a worker node taking several minutes to become available to the kube-scheduler.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1309&quot;&gt;Suppose you need a cluster autoscaler to work with peak demands. In that case, you must resort to deploying a sacrificial buffer of “pause pods” (described in the cluster autoscaler documentation.) When new workloads need those resources, the kube-scheduler immediately evicts the pause pods to free up resources. The cluster later scales up the number of workers to reallocate the evicted pods.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;bace&quot;&gt;&lt;img class=&quot;graf-image&quot; data-height=&quot;678&quot; data-image-id=&quot;1*_c9YTMU5o0dC8TJRHZ1doQ.png&quot; data-width=&quot;1641&quot; height=&quot;264&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*_c9YTMU5o0dC8TJRHZ1doQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Cluster autoscaling enters the picture once pod autoscalers can no longer find enough room on cluster worker&amp;nbsp;nodes.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;76c5&quot;&gt;Also, note that Kubernetes &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/&quot; href=&quot;https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;taints and tolerations&lt;/strong&gt;&lt;/a&gt; also play a role in how autoscalers do their work, making tainted worker nodes off-limits for the placement of certain pods.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;398b&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;abed&quot;&gt;Serverless: Limitless capacity…with limits&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f71d&quot;&gt;For the ultimate level of autoscaling, it is time to abandon the boundaries of a cluster — even Kubernetes &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/setup/best-practices/cluster-large/&quot; href=&quot;https://kubernetes.io/docs/setup/best-practices/cluster-large/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;has limits&lt;/a&gt; — and look at serverless capabilities at the cloud provider level.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b002&quot;&gt;Major cloud providers can spin up container images on demand based on multiple events, such as web requests, database operations, and timers. Their capacity is virtually limitless, with almost negligible cost compared to running the same workload inside a cluster.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;69a0&quot;&gt;Ironically, despite an ultra-low-cost per invocation, serverless approaches make you switch from worrying about resource limits to worrying about cost overruns:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;3800&quot;&gt;Container limits still matter: Cloud providers require you to indicate the number of CPUs and the amount of memory for each container invocation.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;7d51&quot;&gt;Budget limits: Where a bug in a test suite may exhaust cluster capacity, &lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;that same bug in a serverless deployment may erase your entire department’s budget overnight&lt;/strong&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;86ac&quot;&gt;You may find several variants of serverless offerings, such as handing a small function to the cloud engine rather than an entire container image or letting the cloud provider use one of your managed clusters to run the containers (trading scale for security.)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;154b&quot;&gt;For added convenience, many of these offerings can start from a Git repo containing a Dockerfile, then build and cache the container image for when the first invocations arrive.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;bb43&quot;&gt;&lt;img class=&quot;graf-image&quot; data-height=&quot;446&quot; data-image-id=&quot;1*gtVIRo1f0mOuFCip8NJwdA.png&quot; data-width=&quot;738&quot; height=&quot;387&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*gtVIRo1f0mOuFCip8NJwdA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;There are no concerns about cluster capacity with serverless allocation at the cloud provider. System administrators still need to worry about individual containers having enough resources while also focusing on near-infinite runaway resource utilization.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;38a7&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;7c73&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0fba&quot;&gt;We covered the entire spectrum of resource allocation for a workload, from tuning a single container to hyperscaling a workload outside Kubernetes.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;47bf&quot;&gt;The article started with a recap of Kubernetes resource management and its core concepts of &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;resource requests and limits&lt;/strong&gt;. We then built upon those static limits into the realm of &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;pod autoscalers&lt;/strong&gt;, such as HPA, VPA, and KPA.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;aef1&quot;&gt;From pod autoscalers’ ability to efficiently utilize a cluster’s maximum capacity, we moved on to increase that capacity with &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;cluster autoscaling&lt;/strong&gt;. We then completed the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://hitchhikers.fandom.com/wiki/Total_Perspective_Vortex&quot; href=&quot;https://hitchhikers.fandom.com/wiki/Total_Perspective_Vortex&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;total perspective vortex&lt;/a&gt; with &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;virtually unlimited resources&lt;/strong&gt; (and costs) in the form of &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;serverless&lt;/strong&gt; offerings across cloud providers.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;97f2&quot;&gt;Except for VPA, these techniques still build upon &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;reasonable effort to determine a container’s resource consumption during development activities&lt;/strong&gt;. For example, HPA does not take action based on resources where the limits are not specified. Cloud providers outright ask for the CPU and memory resources assigned to each container run.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0103&quot;&gt;With the landscape of resource scaling out of the way, my next article will cover concrete techniques to identify resource requests and limits during development and keep a watchful eye on them in production.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;5773&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;bac3&quot;&gt;References&lt;/h3&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;271b&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://practicalkubernetes.blogspot.com/&quot; href=&quot;https://practicalkubernetes.blogspot.com/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Practical Kubernetes &lt;/a&gt;— &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://practicalkubernetes.blogspot.com/2021/12/top-ten-challenges-part-6-sizing-and.html&quot; href=&quot;https://practicalkubernetes.blogspot.com/2021/12/top-ten-challenges-part-6-sizing-and.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Top Ten Challenges — Part 6: Sizing and Footprint Optimization&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;64f8&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://medium.com/infrastructure-adventures/vertical-pod-autoscaler-deep-dive-limitations-and-real-world-examples-9195f8422724&quot; href=&quot;https://medium.com/infrastructure-adventures/vertical-pod-autoscaler-deep-dive-limitations-and-real-world-examples-9195f8422724&quot; target=&quot;_blank&quot;&gt;Vertical Pod Autoscaler deep dive, limitations and real-world examples&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;7970&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://povilasv.me/vertical-pod-autoscaling-the-definitive-guide/#&quot; href=&quot;https://povilasv.me/vertical-pod-autoscaling-the-definitive-guide/#&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Vertical Pod Autoscaling: The Definitive Guide&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;9a34&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/&quot; href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Kubernetes Workload Resources&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;d6ed&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://cloud.ibm.com/docs/codeengine?topic=codeengine-getting-started&quot; href=&quot;https://cloud.ibm.com/docs/codeengine?topic=codeengine-getting-started&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;IBM Code Engine&lt;/a&gt; (Managed Knative)&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;47c3&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://aws.amazon.com/fargate/&quot; href=&quot;https://aws.amazon.com/fargate/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;AWS Fargate&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/5249933657098121250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/05/infinite-scaling-with-containers-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5249933657098121250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5249933657098121250'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/05/infinite-scaling-with-containers-and.html' title='Infinite scaling with containers and Kubernetes: The total perspective vortex'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Raleigh, NC, USA</georss:featurename><georss:point>35.7795897 -78.6381787</georss:point><georss:box>7.469355863821157 -113.7944287 64.089823536178841 -43.4819287</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-4583749410499172864</id><published>2022-04-21T09:48:00.002-07:00</published><updated>2022-05-12T09:00:21.939-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="argocd"/><category scheme="http://www.blogger.com/atom/ns#" term="gitops"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><title type='text'>Six critical blindspots while securing Argo CD</title><content type='html'>&lt;p&gt;(I originally posted this article on&amp;nbsp;&lt;a href=&quot;https://dnastacio.medium.com/gitops-argocd-security-cbb6fb6378bb&quot; target=&quot;_blank&quot;&gt;medium.com&lt;/a&gt;)&lt;/p&gt;&lt;div&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8552&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2438&quot;&gt;Lately, I have been addressing security risks in our local GitOps deployments, specifically around Argo CD* control planes.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a3f2&quot;&gt;GitOps frameworks like Argo CD run with elevated privileges relative to target deployments, making them prime targets for supply chain attacks.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4488&quot;&gt;Keeping systems secure is a continuous effort over time. This article shows the core strategies for securing an Argo CD deployment and keeping you ahead of potential exposures. If you are new to Argo CD, you may want to read it side-by-side with the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Argo CD security manual&lt;/a&gt;.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;a729&quot;&gt;&lt;img alt=&quot;System administrator sits at expansive network control center wearing headphones and listening to music. A hacker crouches in a corner typing commands. A robot carries out the commands on a deployment environment without catching the attention of the system administrator.&quot; class=&quot;graf-image&quot; data-height=&quot;460&quot; data-image-id=&quot;1*XkUcqmEyRtNUOnnUa_djkA.png&quot; data-width=&quot;1059&quot; height=&quot;278&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*XkUcqmEyRtNUOnnUa_djkA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;GitOps control planes have elevated privileges on entire deployment environments, making them a prime target for supply chain&amp;nbsp;attacks.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;656d&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;beea&quot;&gt;Applications and&amp;nbsp;Projects&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9a45&quot;&gt;Before diving into risk analysis, it is helpful to briefly mention Argo CD’s basic deployment unit: &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#applications&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#applications&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Applications&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3e98&quot;&gt;An Argo CD Application combines a source location (Git URL, revision, and folder containing resources) and a target destination (a namespace in a Kubernetes cluster.)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3188&quot;&gt;Authorized users add applications to an Argo CD &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/projects/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/projects/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Project&lt;/strong&gt;&lt;/a&gt;. An administrator configures a project to restrict the range of sources and destinations in applications and creates access control lists of people authorized to work with the applications in the project.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6e8c&quot;&gt;In addition to these capabilities, I also like that one can issue scoped tokens from a project and use them on external CIs, much like GitHub access tokens.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;3209&quot;&gt;&lt;img alt=&quot;Diagram with big “Project X” box at the center and arrows leading to the concepts contained in an Argo CD project: source repository, whitelisted resources that can be present in Applications in that project, a group of people who can manage the project, and finally, a block of clusters that act as destinations.&quot; class=&quot;graf-image&quot; data-height=&quot;588&quot; data-image-id=&quot;1*b1KOAk8b7NrI8p4VRp2Caw.png&quot; data-width=&quot;1812&quot; height=&quot;208&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*b1KOAk8b7NrI8p4VRp2Caw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;An Argo CD project combines user permissions, lists of allowed resources, source repositories, and destination clusters.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;2228&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;1019&quot;&gt;Lesson #1: Use a dedicated project for the control&amp;nbsp;plane&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d483&quot;&gt;This lesson assumes that you manage the Argo CD control plane through GitOps — how else, right?&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e00d&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why it matters:&lt;/strong&gt; Without a dedicated project for the control plane, a project shared with other applications allows those applications to manage workloads inside the Argo CD namespace.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;46d3&quot;&gt;The corresponding application resource(s) for the control plane must target the location of the control plane squarely with the following fields:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;7c5b&quot;&gt;&lt;code class=&quot;markup--code markup--li-code&quot;&gt;spec.destination.server&lt;/code&gt; refers to the local cluster: https://kubernetes.default.svc&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;909c&quot;&gt;&lt;code class=&quot;markup--code markup--li-code&quot;&gt;spec.destination.namespace&lt;/code&gt; refers to the namespace where the Argo CD instance is running.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f06d&quot;&gt;The dedicated project should be configured with the following settings:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;3779&quot;&gt;&lt;code class=&quot;markup--code markup--li-code&quot;&gt;spec.sourceRepos[]&lt;/code&gt; refers to the Git repositories managed by the instance owners and only those repositories containing the control plane’s configuration.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;a943&quot;&gt;&lt;code class=&quot;markup--code markup--li-code&quot;&gt;spec.destinations[0].server&lt;/code&gt; refers to the local cluster: &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://kubernetes.default.svc&quot; href=&quot;https://kubernetes.default.svc&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;https://kubernetes.default.svc&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f6e7&quot;&gt;&lt;code class=&quot;markup--code markup--li-code&quot;&gt;spec.destinations[0].namespace&lt;/code&gt; refers to the namespace running the Argo CD instance&lt;/li&gt;&lt;/ul&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;4759&quot;&gt;&lt;img alt=&quot;A diagram with a “Project control-plane” at the center, with an arrow to a “control-gitops” GitOps repository, a reference to the local cluster, and an arrow to a sticky figure sitting at a desk and typing configuration files, representing an Argo administrator.&quot; class=&quot;graf-image&quot; data-height=&quot;668&quot; data-image-id=&quot;1*6lwMKkPjNV7xdgdEM9qVjw.png&quot; data-is-featured=&quot;true&quot; data-width=&quot;1593&quot; height=&quot;268&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*6lwMKkPjNV7xdgdEM9qVjw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;A dedicated project for managing the Argo CD instance allows administrators to separate applications that require elevated privileges from other applications meant to manage other resources.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ed73&quot;&gt;No other project in the instance should have that same combination of server and namespace in its &lt;code class=&quot;markup--code markup--p-code&quot;&gt;destinations&lt;/code&gt; field.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e05d&quot;&gt;Note that the attack surface of the control plane &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;extends to the Git repository hosting the control-plane resources&lt;/strong&gt;. In that sense, Argo CD administrators must also be well-versed in managing and securing Git repositories.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;59cf&quot;&gt;Securing a GitOps repository is a topic that deserves its own future article. For now, I suggest a minimum of:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;96e1&quot;&gt;Making the repository private.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;e5be&quot;&gt;Enabling branch protection on the main development branch of the &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://medium.com/p/fcfdb5b3e34d&quot; href=&quot;https://medium.com/p/fcfdb5b3e34d&quot; target=&quot;_blank&quot;&gt;CI pipeline&lt;/a&gt;.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;015f&quot;&gt;Requiring signed commits.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;4e90&quot;&gt;Requiring code reviews before merging branches.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;c45d&quot;&gt;Restricting who can push to the main development branch.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;99c3&quot;&gt;Adding automated processing to lint pull requests, labeling the pull request as sensitive if it contains changes that affect access control, such as roles and role bindings.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;e967&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;bd76&quot;&gt;Lesson #2: Argo resources are for Argo admins&amp;nbsp;only&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3b31&quot;&gt;Only GitOps repositories owned by Argo CD administrators should contain resources belonging to the &lt;code class=&quot;markup--code markup--p-code&quot;&gt;argoproj.io&lt;/code&gt; API group.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8c6c&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why it matters: &lt;/strong&gt;Popular Argo tutorials contain resources like &lt;code class=&quot;markup--code markup--p-code&quot;&gt;ApplicationSet.argoproj.io&lt;/code&gt; and &lt;code class=&quot;markup--code markup--p-code&quot;&gt;Application.argoproj.io&lt;/code&gt;. These resources require their projects to allow the creation of other resources in the same namespace as the Argo CD instance.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;977e&quot;&gt;Multiple users consider this lesson quite restrictive, but that is the current security model. The chain of explanations goes as follows:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;4846&quot;&gt;Argo CD only recognizes Application resources in the namespace hosting the Argo CD instance (&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/issues/3847&quot; href=&quot;https://github.com/argoproj/argo-cd/issues/3847&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;see discussion in this issue&lt;/a&gt;.)&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;912f&quot;&gt;From the previous point, a Project containing Application resources must include the namespace of the Argo CD instance in its &lt;code class=&quot;markup--code markup--li-code&quot;&gt;destinations&lt;/code&gt; field (&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/issues/8982#issuecomment-1098414487&quot; href=&quot;https://github.com/argoproj/argo-cd/issues/8982#issuecomment-1098414487&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;see this other discussion&lt;/a&gt;.)&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;0fa8&quot;&gt;Since that &lt;code class=&quot;markup--code markup--li-code&quot;&gt;destinations&lt;/code&gt; field applies to the contents of all repositories in the project, only Argo CD admins or delegates can merge pull requests in those repositories.&lt;/li&gt;&lt;/ol&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;690c&quot;&gt;You can read the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/issues/8982#issuecomment-1098414487&quot; href=&quot;https://github.com/argoproj/argo-cd/issues/8982#issuecomment-1098414487&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;detailed discussion in this issue&lt;/a&gt;, which led to proposals calling for further attention on both &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/pull/9096&quot; href=&quot;https://github.com/argoproj/argo-cd/pull/9096&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/issues/8985&quot; href=&quot;https://github.com/argoproj/argo-cd/issues/8985&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;the user interface&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8be0&quot;&gt;Beyond calling attention to this common security blind spot, there are proposals to tighten the security privileges of an Application within an instance, such as &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/issues/7689&quot; href=&quot;https://github.com/argoproj/argo-cd/issues/7689&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;issue 7689&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;6df8&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;0b06&quot;&gt;Lesson #3: Delete the “default” project&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;be22&quot;&gt;Argo CD’s initial configuration has a &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/projects/#the-default-project&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/projects/#the-default-project&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“default” project&lt;/a&gt;. This project allows authorized users to add applications from any source repository and manage all resources on all destinations.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;afe3&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why it matters:&lt;/strong&gt; A malicious or poorly designed Application may contain resources that alter the configuration of the entire cluster. The service accounts used to run Argo CD are often privileged enough to oblige.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b317&quot;&gt;That configuration is ideal for a non-production Argo CD instance tuned for fast progress during a learning session. It is also the stuff of nightmares for an unsuspecting system administrator.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;be60&quot;&gt;&lt;img alt=&quot;Diagram with a big box labeled “Project default”, referencing multiple repositories with a bomb icon next to them and a sticky figure with a mask and in a suspicious manner. The project also has an arrow pointing at destinations, with some of them containing the same bomb icon seen in the source repositories.&quot; class=&quot;graf-image&quot; data-height=&quot;549&quot; data-image-id=&quot;1*HBfzflT5BII5__Lfqp5X7Q.png&quot; data-width=&quot;1308&quot; height=&quot;269&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*HBfzflT5BII5__Lfqp5X7Q.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;The “default” application project in Argo CD allows applications from all sources to manage resources on all destinations. It is meant solely for learning purposes in a disposable environment.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0a36&quot;&gt;A cluster may still reject requests due to its own &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/rbac/&quot; href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/rbac/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;RBAC permissions&lt;/a&gt;, but removing broad permissions is an essential first line of defense for the control plane.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2170&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Note&lt;/strong&gt;: The Argo CD UI prevents the deletion of the project, so delete the project directly using &lt;code class=&quot;markup--code markup--p-code&quot;&gt;kubectl delete AppProject default -n ${argocd_namespace:?}&lt;/code&gt;. Alternatively, you may edit out all of the &lt;code class=&quot;markup--code markup--p-code&quot;&gt;*&lt;/code&gt; permissions from the project.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;4aea&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;79ee&quot;&gt;Lesson #4: Block ClusterRoleBindings in (most)&amp;nbsp;projects&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7779&quot;&gt;The previous lessons prevent unauthorized repository owners from commandeering an Argo CD instance. This lesson is about protecting the cluster itself.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3e70&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why it matters: &lt;/strong&gt;Applications managing &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding&quot; href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;ClusterRoleBindings&lt;/a&gt; can attach privileged cluster roles to a service account, later using that account in pods running &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/resource_hooks/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;resource hooks&lt;/a&gt; to execute privileged actions.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8d36&quot;&gt;The only potential exception to this rule is when a dedicated Argo CD project is assigned to the cluster administrators.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a40c&quot;&gt;While we all have dealt with our share of products requiring admin-level privileges during their installation, blocking these resources at the project level forces meaningful conversations between product and cluster admins.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;07cb&quot;&gt;These conversations can lead to safer arrangements, with narrower roles tied to separate service accounts and managed in git repositories owned by cluster administrators.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8db8&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;3743&quot;&gt;Lesson #5: Narrow roles on remote&amp;nbsp;clusters&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f47a&quot;&gt;Argo CD offers distinct deployment topologies where an instance can control anything from the local cluster to a fleet of remote clusters.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;52b0&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why it matters: &lt;/strong&gt;If the Argo CD control plane is compromised, narrower permissions assigned to a dedicated service account in the remote cluster will limit the exposure and speed up recovery efforts.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d202&quot;&gt;When adding remote clusters to the list of destinations in Argo CD, I suggest spending a few minutes discussing the following points with the cluster administrators:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;c5c0&quot;&gt;Determine the list of namespaces in the cluster that the Kubernetes administrators want to manage with Argo CD applications. Is it the whole cluster, or is it specific namespaces?&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;87e7&quot;&gt;Ask the Kubernetes administrator to create a dedicated service account in each cluster, such as “argocd-control-plane-account.”&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;9d78&quot;&gt;Ask the Kubernetes administrator to bind that service account to a role or roles) that match the specific namespaces discussed in the previous steps. Full permissions in the entire namespace may be acceptable. Still, one may consider narrower permissions depending on the scenario (for instance, not granting permissions to read &lt;code class=&quot;markup--code markup--li-code&quot;&gt;secret&lt;/code&gt; resources.)&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f0c3&quot;&gt;Ask the Kubernetes administrator to generate the “kubeconfig” file from that service account, then use that file when adding the cluster to Argo CD.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;e18d&quot;&gt;Agree on the rotation interval for the service account tokens and the process to replace them in Argo.&lt;/li&gt;&lt;/ol&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;fdd8&quot;&gt;&lt;img alt=&quot;Two-part figure. On the left, a Kubernetes administrator stares at 3 boxes, representing clusters. Each box has a hole with a different shape, representing portions of the the cluster that will be managed with GitOps. On the right, the Kubernetes administrator carries a stack of papers representing credentials for those three portions, with “90 days” written on top of the stack. A sitting Argo CD administrator uses those instructions to type commands starting with “argocd cluster add”.&quot; class=&quot;graf-image&quot; data-height=&quot;564&quot; data-image-id=&quot;1*S80b71r-QSGJIV_ybgltNw.png&quot; data-width=&quot;1611&quot; height=&quot;224&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*S80b71r-QSGJIV_ybgltNw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Cluster administrators should create dedicated service accounts with the narrowest possible roles before handing “kubeconfig” files to Argo CD administrators.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8539&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;e5bb&quot;&gt;Lesson #6: Have a CVE response plan&amp;nbsp;ready&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f3be&quot;&gt;Like any software component, GitOps frameworks may suffer from vulnerability and exposures, and mitigating those risks requires awareness and speed.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2061&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why it matters:&lt;/strong&gt; Having a response plan in place expedites the assessment of the situation and eventual recovery efforts.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;53f4&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/security/advisories&quot; href=&quot;https://github.com/argoproj/argo-cd/security/advisories&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;ArgoCD publishes its CVEs&lt;/a&gt; as &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://docs.github.com/en/code-security/repository-security-advisories/about-github-security-advisories-for-repositories&quot; href=&quot;https://docs.github.com/en/code-security/repository-security-advisories/about-github-security-advisories-for-repositories&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitHub security advisories&lt;/a&gt;, making it easier to stay on top of new developments. It is also good to familiarize yourself with Argo CD issues &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/argoproj/argo-cd/issues?q=is%3Aissue+is%3Aopen+label%3Asecurity&quot; href=&quot;https://github.com/argoproj/argo-cd/issues?q=is%3Aissue+is%3Aopen+label%3Asecurity&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;labeled with the “security” tag&lt;/a&gt; to stay ahead of new developments and help shape their progress with comments and suggestions.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1b85&quot;&gt;As a consumer of these frameworks, there is no fixed recipe for responding to such advisories. The best strategy is to read through sections related to workarounds and mitigations and implement those recommendations as quickly as possible.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;a3ef&quot;&gt;&lt;img alt=&quot;Left side of figure has sticky figure with a megaphone announces a new CVE. Right side of figure has administrators frantically trying to apply mitigations and patches.&quot; class=&quot;graf-image&quot; data-height=&quot;429&quot; data-image-id=&quot;1*UtKeuiq2agaCbs-u-DJtgg.png&quot; data-width=&quot;1161&quot; height=&quot;236&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*UtKeuiq2agaCbs-u-DJtgg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Once a CVE is announced, administrators should be ready to react quickly with patches and mitigations.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fbd1&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Patching a CVE is not sufficient.&lt;/strong&gt; The next step is to determine whether someone may have exploited the CVE. The assessment, at a minimum, should involve these steps:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;9dda&quot;&gt;Inspect &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/#auditing&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/#auditing&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Argo-generated audit events&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/#logging&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/#logging&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;logs of calls&lt;/a&gt; related to applications used to manage the control plane.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;4c5f&quot;&gt;Revisit all roles and role bindings in the cluster hosting the control plane.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;7e73&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;8ace&quot;&gt;Summary&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a7b4&quot;&gt;Argo CD’s out-of-the-box permissions are tuned for a quick on-ramp into learning exercises. &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;They are unsuited for production environments and &lt;/strong&gt;compounded by many early adopters &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;not realizing the security implications of using the popular “&lt;/strong&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#app-of-apps&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/#app-of-apps&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;App of Apps&lt;/strong&gt;&lt;/a&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;” pattern&lt;/strong&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2cdb&quot;&gt;Use &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;separate Argo instances&lt;/strong&gt; for individual teams, create a &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;dedicated project for managing Argo, &lt;/strong&gt;and remember to delete the “default” project.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1fd3&quot;&gt;When separate teams manage remote clusters, &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;discuss service accounts’ roles and token rotation policies with the Kubernetes administrators&lt;/strong&gt; before registering the clusters as destinations in Argo.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;084a&quot;&gt;And finally, be prepared to monitor and react to Argo vulnerabilities with &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;validated plans for mitigating the risks outlined in a CVE&lt;/strong&gt; and post-incident assessments about eventual exploits in your systems.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;301c&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;7bcd&quot;&gt;References&lt;/h3&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;91b1&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/security/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Argo CD, security manual&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;3461&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://blog.argoproj.io/best-practices-for-multi-tenancy-in-argo-cd-273e25a047b0&quot; href=&quot;https://blog.argoproj.io/best-practices-for-multi-tenancy-in-argo-cd-273e25a047b0&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Best Practices for Multi-tenancy in Argo CD&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;97b5&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://opengitops.dev/blog/sec-gitops&quot; href=&quot;https://opengitops.dev/blog/sec-gitops&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Security best practices for GitOps&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f580&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://dnastacio.medium.com/why-you-should-avoid-sealed-secrets-in-your-gitops-deployment-e50131d360dd?source=friends_link&amp;amp;sk=ccfe406e91e3b03c3893bc492082f1c3&quot; href=&quot;https://dnastacio.medium.com/why-you-should-avoid-sealed-secrets-in-your-gitops-deployment-e50131d360dd?source=friends_link&amp;amp;sk=ccfe406e91e3b03c3893bc492082f1c3&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Why you should avoid Sealed Secrets in your GitOps deployment&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;section class=&quot;section section--body&quot; name=&quot;66ab&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/4583749410499172864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/04/six-critical-blindspots-while-securing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/4583749410499172864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/4583749410499172864'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/04/six-critical-blindspots-while-securing.html' title='Six critical blindspots while securing Argo CD'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Raleigh, NC, USA</georss:featurename><georss:point>35.7795897 -78.6381787</georss:point><georss:box>8.2713122045790826 -113.7944287 63.287867195420922 -43.4819287</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-923344240472921016</id><published>2022-03-31T20:30:00.013-07:00</published><updated>2022-05-11T07:38:09.580-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="argocd"/><category scheme="http://www.blogger.com/atom/ns#" term="gitops"/><category scheme="http://www.blogger.com/atom/ns#" term="helm"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="kustomize"/><title type='text'>Kustomize and GitOps: The Good, the Bad, and the Ugly</title><content type='html'>&lt;p&gt;&amp;nbsp;(I originally posted this article on &lt;a href=&quot;http://medium.com&quot; target=&quot;_blank&quot;&gt;medium.com&lt;/a&gt;)&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;66ab&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4afc&quot;&gt;Teams adopting GitOps invariably face a handful of pivotal decisions in their path, such as the choice of GitOps framework and how to design repositories to match their deployment workflows.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7dd0&quot;&gt;In a Kubernetes-based shop, that framework is probably either ArgoCD or FluxCD, which are adept at detecting and correcting configuration drift between the repositories and the target clusters.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;3a84&quot;&gt;&lt;img alt=&quot;Two-part picture. The figure on the left shows a robot startled while looking at a difference between contents on a Git repository folder and the configuration of a Kubernetes cluster. The figure on the right shows the robot replicating the change on the Kubernetes cluster.&quot; class=&quot;graf-image&quot; data-height=&quot;363&quot; data-image-id=&quot;1*MORkwV0-m161V02ApLJk5g.png&quot; data-width=&quot;1280&quot; height=&quot;182&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*MORkwV0-m161V02ApLJk5g.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;A GitOps framework’s primary job is to detect “drift” between the desired configuration in a Git repo and the actual settings in a deployment.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;0d8f&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;a7e0&quot;&gt;What you see is almost what you&amp;nbsp;get.&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c1a7&quot;&gt;While these frameworks can apply the literal contents of a Git repository to a target Kubernetes cluster, those contents are likely to need adjustments to fit most common scenarios.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1ce2&quot;&gt;For example, assume a system with five production environments where the only difference in the configuration for each cluster is the number of worker nodes. It would be challenging to maintain one complete copy of the folder per cluster over time, with authors mindlessly replicating changes and pull request reviewers droning over duplicate content.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;dbba&quot;&gt;&lt;img alt=&quot;A picture of five file folders with four identical attributes and one tiny difference in the fifth attribute. Sticky figure scratching head while staring at folders.&quot; class=&quot;graf-image&quot; data-height=&quot;593&quot; data-image-id=&quot;1*3QJp4q6BYL-klJLkozIJ_Q.png&quot; data-is-featured=&quot;true&quot; data-width=&quot;1498&quot; height=&quot;253&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*3QJp4q6BYL-klJLkozIJ_Q.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Copying-pasting folder contents may be the fastest way to bootstrap a new environment but will make maintenance more challenging over&amp;nbsp;time.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;40a1&quot;&gt;These Kubernetes-based GitOps frameworks offer internal configuration management pipelines as a common strategy to avoid these tedious and error-prone repetitions. The pipelines transform the repository’s contents before applying the results to the destination — while Flux CD uses the term “pipelines,” Argo CD refers to these transformations as &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/build-environment/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/build-environment/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“build environments.”&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;209e&quot;&gt;The primary choices for transformation pipelines are Kustomize and Helm. ArgoCD also supports the less popular &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://jsonnet.org/&quot; href=&quot;https://jsonnet.org/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;JSONNet framework&lt;/a&gt; and the concept of custom configuration management plugins (CMP.) JSONNet, with its object-oriented approach, is peculiar enough to deserve a separate closer look, while I have a word or two about CMPs towards the end.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;5d63&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;d7b4&quot;&gt;How does Kustomize work?&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;553d&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kustomize.io/&quot; href=&quot;https://kustomize.io/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Kustomize&lt;/a&gt; uses a configuration file named kustomization.yaml to transform the contents of a directory or GitHub URL. In its simplest form, a kustomization.yaml file has the list of files from the source directory. Running the kustomize command-line interface with that file against a local folder or remote Git URL yields the contents of the files in that list.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;b085&quot;&gt;&lt;img alt=&quot;Folder with many YAML files and a file named “kustomization.yaml” with a bulleted list of a few of those files.&quot; class=&quot;graf-image&quot; data-height=&quot;593&quot; data-image-id=&quot;1*tP752ZWdLTsGN3C_rRKIJg.png&quot; data-width=&quot;1632&quot; height=&quot;232&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*tP752ZWdLTsGN3C_rRKIJg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Kustomize uses a kustomization.yaml file and a base folder as sources. The kustomize CLI uses the kustomization.yaml file to decide which files to process and how to modify&amp;nbsp;them.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;078e&quot;&gt;Kustomize’s capabilities grow from there, with &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization&quot; href=&quot;https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;features&lt;/a&gt; such as adding a set of annotations to all resources, generating new ConfigMaps and Secrets based on a seed file, modifying select portions of resources, and a few others.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2294&quot;&gt;Kustomize meets most imaginable configuration scenarios, as long as you are willing to put effort into specific areas. The question addressed in later sections is whether that effort pays off during regular interactions with the repository, such as authoring and reviewing pull requests.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;7371&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;9cb4&quot;&gt;Helm charts, the&amp;nbsp;basics&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ab16&quot;&gt;Helm charts offer a higher-level abstraction than Kustomize, centered around the concept of “&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://helm.sh/docs/chart_template_guide/getting_started/&quot; href=&quot;https://helm.sh/docs/chart_template_guide/getting_started/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Charts&lt;/a&gt;.” At the core, a chart is a combination of files in a folder named “templates” and a “values.yaml” file. The “templates” folder contains Kubernetes resources, just like in Kustomize, but Helm can substitute optional templating statements inside each file with contents from various sources.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b661&quot;&gt;The &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://helm.sh/docs/chart_template_guide/values_files/&quot; href=&quot;https://helm.sh/docs/chart_template_guide/values_files/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;templating statements&lt;/a&gt; can be as simple as a reference to a variable declared in the “values.yaml” file but can grow in complexity with flow controls, built-in functions, and named templates.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;195b&quot;&gt;&lt;img alt=&quot;Picture of a folder with a “templates” folder and a “values.yaml” file. The “templates” folder has many files in it. An inset of one of the files shows a couple of variable declarations and the value declared inside “values.yaml”&quot; class=&quot;graf-image&quot; data-height=&quot;725&quot; data-image-id=&quot;1*69e7SmEctFODSzMKcYXfAQ.png&quot; data-width=&quot;1300&quot; height=&quot;357&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*69e7SmEctFODSzMKcYXfAQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Helm transformations revolve around a folder named “templates” with resources and a file named values.yaml. Helm looks for templating statements and replaces them with values such as variables and contents from other resources.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2746&quot;&gt;After covering the basics of Kustomize and Helm, it is time to explore the Good, the Bad, and the Ugly of each approach in the context of a GitOps practice.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;c5ba&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;4ba9&quot;&gt;The Good #1: Kustomize as a library&amp;nbsp;cart.&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c7a6&quot;&gt;If your organization has a curated library of configuration resources, Kustomize is an ideal companion to select elements from that library. Add only the filenames of the resources you need into a kustomization.yaml file, indicate the Git URL (and “ref”&amp;nbsp;!) of the folders containing the resources, and the Kustomize pipeline inside Argo CD or Flux CD will apply those resources to the target system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;99ac&quot;&gt;Although Helm can achieve the same result of applying select resources from an extensive repository, both &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/helm/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/helm/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Argo&lt;/a&gt; and &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://fluxcd.io/docs/guides/helmreleases/&quot; href=&quot;https://fluxcd.io/docs/guides/helmreleases/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Flux&lt;/a&gt; require the creation of a wrapper resource for each Chart.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;e793&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;8406&quot;&gt;The Good #2: What you see (in the files) is what you&amp;nbsp;get.&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;67e3&quot;&gt;One of the core premises of a GitOps practice is to manage system configuration using a Git repository. While it is virtually impossible to represent all configuration levers for a Kubernetes cluster, let alone for the entire infrastructure, Kustomize’s design relies solely on configuration files as the input to manage configuration.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4a60&quot;&gt;As evidence of Kustomize’s opinionated approach to data sources, the only way to specify the value for a variable mentioned in a file is to provide another file with that value.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7979&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;No ambiguity. &lt;/strong&gt;To take its opinionated approach a step further, Kustomize requires that repository owners be precise about the “address” of the change, specifying the type of resource and the respective location of patches and replacements. That specificity virtually eliminates ambiguity and the potential for a change accidentally causing unexpected side-effects elsewhere in the results of a kustomize transformation.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;52e7&quot;&gt;As a result, one can be confident about the resulting configuration after applying Kustomize to the contents of a GitOps repository by looking solely at the repository and without consulting any other source.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;e600&quot;&gt;&lt;img alt=&quot;Side-by-side drawing of a folder with a Kubernetes Job resource and a kustomization.yaml file containing a “resources” element selecting the file for the Job resource and a long “replacements” field targeting a secret deep inside a “container” element inside the Job specification.&quot; class=&quot;graf-image&quot; data-height=&quot;1092&quot; data-image-id=&quot;1*WmeM3T4e5wIJ7QYDnzpoRw.png&quot; data-width=&quot;2326&quot; height=&quot;300&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*WmeM3T4e5wIJ7QYDnzpoRw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Kustomize’s design calls for a deterministic selection of resources based on a precise selection of resource types, names, and field locations.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a078&quot;&gt;Contrast that certainty with Helm’s approach to &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;templating&lt;/strong&gt;, where the invoker of the Helm command-line interface can override any variable in the values.yaml file with a command-line parameter. Helm propagates that value to all occurrences of the variable name anywhere in the Chart, with the semantics of simple text replacement and not a hint of type awareness.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4672&quot;&gt;While convenient, that flexibility means a pull request reviewer may feel inclined to reject a change if they cannot tell whether a variable value in the Chart may compromise the system, such as a variable name representing the role reference in a ClusterRoleBinding resource.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;29cf&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;c6cc&quot;&gt;The Bad: Mixing filesystems with Kubernetes concepts&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;07ab&quot;&gt;While I appreciate the simplicity of a file-based approach to select resources, there is some conceptual back-and-forth between filesystems and Kubernetes CRDs when reading a Kustomize-based repository.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a5c1&quot;&gt;Surely, we can expect a GitOps practitioner to know their way around both concepts, but that kind of context-switching reduces productivity for pull request reviewers.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6f9d&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Is it a file or a resource?&lt;/strong&gt; For example, the entry-level construct &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/resource/&quot; href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/resource/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“resources”&lt;/a&gt; locates resources by filename. At the same time, an element such as &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/&quot; href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“patches”&lt;/a&gt; follows the conceptual model of Kubernetes patches, with meta-references to fields in a custom resource definition. Sitting in between filesystems and patches, we find elements such as “replacements,” combining some addressability concepts from patching and what looks like JSON selectors.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;e840&quot;&gt;&lt;img alt=&quot;Sticky figure looks at three files: a.yaml containing a ConfigMap resource, b.yaml containing another ConfigMap resource, and a kustomization.yaml file containing a “resources” element referencing both files. The kustomization.yaml file has a “replacements” section referencing a “ConfigMap”, making the sticky figure wonder which of a.yaml or b.yaml contain matching resources.&quot; class=&quot;graf-image&quot; data-height=&quot;780&quot; data-image-id=&quot;1*rUda8ziTF47Zh_NnhWoADA.png&quot; data-width=&quot;1342&quot; height=&quot;372&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*rUda8ziTF47Zh_NnhWoADA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;A kustomization.yaml file contains a mixture of concepts, with some constructs based on filenames (“resources”) and other constructs based on Go-templating (“replacements”) and a few based on Kubernetes custom resources (some forms of “patches.”)&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4c35&quot;&gt;I know Kustomize advocates may become proficient at the context-switching and consider it just a matter of course when working with configuration management in Kubernetes. Naturally, I would not expect Kustomize to use a constrained file-based approach like the “sed” syntax to modify a file. Still, it is hard to gloss over how reading a Kustomize file calls for the somewhat challenging ability to assemble these different concepts in one’s head, especially when I look at the most common workarounds:&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;06e9&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“You could run the kustomize CLI to see the results instead of trying to read the source.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0493&quot;&gt;At that point, I am already going outside the GitOps tooling to work around the problem, cloning the branch for pull requests and figuring out the correct parameters to invoke kustomize.&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;7c5a&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“A CI/CD action could run the kustomize CLI and show the differences in the context of the pull request review.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6505&quot;&gt;A bot showing the outcome of the kustomize output between the source and target branches, even when integrated into something like the “Checks” tab of a pull request in GitHub, does not tell me the source files and lines where the changes originated. At that point, that is a review of a deployment plan instead of a pull request review.&lt;/p&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;7c81&quot;&gt;The Ugly #1: Dealing with variable replacements&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c1fe&quot;&gt;The same opinionated philosophy that makes Kustomize-based repositories self-contained and prescriptive during operations makes Kustomize brittle when dealing with everyday situations.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;636a&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Replace with “replacements.”&lt;/strong&gt; With &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/vars/&quot; href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/vars/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“vars” being deprecated&lt;/a&gt;, one must pause to take in the complexity of its functional replacement, which is coincidentally and unironically named &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/replacements/&quot; href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/replacements/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“replacements.”&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6732&quot;&gt;I appreciate how a block of code like the one below leaves no margin of doubt about what it will do, but it is hard to overlook the many keywords and metadata references spent on addressing the one field to be replaced.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;ab98&quot;&gt;&lt;img alt=&quot;Developer sitting at a table and frantically coding a large block of a YAML resource with multiple lines of statements to replace a single value in a Job resource.&quot; class=&quot;graf-image&quot; data-height=&quot;1079&quot; data-image-id=&quot;1*s8tXGn-JHC3mX_QsBD6WOA.png&quot; data-width=&quot;1115&quot; height=&quot;619&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*s8tXGn-JHC3mX_QsBD6WOA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Kustomize sometimes makes simple tasks, like replacing a variable inside a resource, labor-intensive and difficult to maintain.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;1b6c&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;f473&quot;&gt;The Ugly #2: File names are (almost)&amp;nbsp;forever&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3028&quot;&gt;The precision with which Kustomize addresses file locations in a repository is its undoing when the time comes for refactoring files and folders.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1dae&quot;&gt;If you have an overlay folder containing a kustomization.yaml file, which includes a “resources” section referencing a few files in a base folder, any change to a filename in that base folder may break the overlay folder.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;bfc4&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Overlay 3rd-party bases at your peril.&lt;/strong&gt; Addressing filename changes is simpler when you own both the overlay and base folders. You presumably have complete control over making changes to both folders simultaneously during a refactoring cycle.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;a4f5&quot;&gt;&lt;img alt=&quot;Sticky figure representing the author of a pull request struggling to move two enormous folders (twice his size) to the right.&quot; class=&quot;graf-image&quot; data-height=&quot;371&quot; data-image-id=&quot;1*St9yAqLwJRwh2alsMB5ZYg.png&quot; data-width=&quot;987&quot; height=&quot;241&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*St9yAqLwJRwh2alsMB5ZYg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Refactoring resources across folders and files is a brittle process, where developers must exercise extreme care in matching every name change with the contents of other&amp;nbsp;files.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;436b&quot;&gt;A less common and dangerous scenario is when the refactoring of a base folder splits the &lt;em class=&quot;markup--em markup--p-em&quot;&gt;contents&lt;/em&gt; of a file into multiple files while preserving the original file’s name. For instance, someone may have placed an extraneous “ClusterRoleBinding” in a file named “roles.yaml”, then versioned the repository, and then refactored that role binding resource into a dedicated “bindings.yaml” file on the next release.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;521e&quot;&gt;That is the kind of change that can easily go unnoticed in a “kustomize” invocation (the “resources” section has the name of a file that still exists,) requiring exquisite levels of attention when updating the reference to a newer version of the “base” folder.&lt;/p&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;b27b&quot;&gt;&lt;strong class=&quot;markup--strong markup--h3-strong&quot;&gt;The Ugly #3: The magic&amp;nbsp;hybrid&lt;/strong&gt;&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ac32&quot;&gt;Argo CD’s custom &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;configuration management plugin&lt;/a&gt;” allows an admin to provide Argo custom code to run the transformation pipeline. One of the samples offered in the guides is a blend of &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://github.com/argoproj/argocd-example-apps/tree/master/plugins/kustomized-helm&quot; href=&quot;https://github.com/argoproj/argocd-example-apps/tree/master/plugins/kustomized-helm&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Kustomize and Helm&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e93b&quot;&gt;At first glance, the idea makes sense: If Kustomize and Helms have strengths and weaknesses, combine both, right? Not really.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;28bd&quot;&gt;Combining both means practitioners have to design (and observe) the boundary where Kustomize ends, and Helm starts. For instance, the design may call for the kustomization.yaml file only allowing the usage of the “resources” clause, deferring everything else to Helm. But what stops a new team member, unaware of that boundary, from using a “replacements” or “patch” annotation to avoid creating another Helm chart?&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;1f32&quot;&gt;&lt;img alt=&quot;Two-part figure. The tree representation of a folder containing a kustomization.yaml file and two Helm charts is on the left. The kustomization.yaml file contains a “resources” section referencing one of the Helm charts. The right side of the picture has two robots carrying two objects, with one of the robots standing on the back of the first.&quot; class=&quot;graf-image&quot; data-height=&quot;442&quot; data-image-id=&quot;1*7JPnnwRAys3oBv4-PjBA0w.png&quot; data-width=&quot;1160&quot; height=&quot;244&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*7JPnnwRAys3oBv4-PjBA0w.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;A custom configuration management plugin can run different commands in a sequence. With great flexibility comes the great need to design, document, and enforce bespoke workflows.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;995e&quot;&gt;Between the overhead of working with two overlapping technologies, constantly toeing the imaginary line between the two, and having to correct eventual boundary crosses, the total cost of ownership for the hybrid approach offsets any productivity gain in leveraging Kustomize in small corners of the repository.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f21f&quot;&gt;There may still be good cases for using those plugins, but making Kustomize and Helm work together isn’t one of them.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;7ee4&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;2d35&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1136&quot;&gt;Kustomize offers advantages when dealing with file selection scenarios, but resource contents invariably need alterations. With Kustomize, those alterations mean reviewers of pull requests staring at stretches of “patches” and “replacements” blocks, ultimately trying to run small Kustomize pipelines in their heads.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b9c3&quot;&gt;Pull request reviewers may often ponder their career choices while deciphering the meaning of &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#patchjson6902&quot; href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#patchjson6902&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“JSON 6902”&lt;/a&gt;, and authors may find themselves wondering whether a custom resource definition tolerates the patch they would like to apply to a resource.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0e0f&quot;&gt;For a discipline like GitOps, which requires frequent adjustments to large folder structures before an agent of some sort can deploy the results to a target cluster, I think Kustomize requires disproportionately greater attention and effort than working with Helm charts.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0dd9&quot;&gt;While I can enjoy the occasional mental gymnastic involved in reconstructing a Helm chart as a Kustomize-based file structure, I remain hard-pressed to pick Kustomize over Helm for all but the most limited use cases in a busy GitOps practice.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;43e6&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;26f0&quot;&gt;References&lt;/h3&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;34f5&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.youtube.com/watch?v=HDg5vh97zmI&quot; href=&quot;https://www.youtube.com/watch?v=HDg5vh97zmI&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitOps Guide to the Galaxy (Ep 23): Directory structure battles&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;1c73&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;The GitOps Files — Repository design pitfalls&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/923344240472921016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/03/kustomize-and-gitops-good-bad-and-ugly.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/923344240472921016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/923344240472921016'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/03/kustomize-and-gitops-good-bad-and-ugly.html' title='Kustomize and GitOps: The Good, the Bad, and the Ugly'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-5897024091103445640</id><published>2022-03-16T20:30:00.003-07:00</published><updated>2022-04-19T10:56:34.124-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cicd"/><category scheme="http://www.blogger.com/atom/ns#" term="gitops"/><category scheme="http://www.blogger.com/atom/ns#" term="k8s"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><title type='text'>Effective CI/CD strategies for GitOps</title><content type='html'>&lt;section class=&quot;section section--body&quot; name=&quot;cba5&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;section class=&quot;section section--body&quot; name=&quot;cba5&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;(I originally posted this article on &lt;a href=&quot;http://medium.com&quot; target=&quot;_blank&quot;&gt;medium.com&lt;/a&gt;)&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1dd9&quot;&gt;With Git at the heart of GitOps, it is natural to consider adopting the core CI/CD concepts of continuous integration, delivery, and deployment to validate changes to a GitOps repository.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;613b&quot;&gt;CI/CD for GitOps still needs a strong focus on automation for validation and rollout steps, but dealing with infrastructure significantly affects the dynamics of these steps to the point where a few revisions are in order. The following sections build upon the lessons from &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5?source=friends_link&amp;amp;sk=f388bc2a35c58be1abcd6bd898bb65bf&quot; href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5?source=friends_link&amp;amp;sk=f388bc2a35c58be1abcd6bd898bb65bf&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;my previous article on GitOps repository design&lt;/a&gt; and highlight the central adaptations for GitOps CI/CD pipelines.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;e2e3&quot;&gt;&lt;img alt=&quot;Person placing box on long conveyor belt rolling to the right, with pile of processed boxes to the right of the conveyor belt.&quot; class=&quot;graf-image&quot; data-height=&quot;267&quot; data-image-id=&quot;1*Yw2XFBvuZAVXjw_drSx7Eg.png&quot; data-width=&quot;1199&quot; height=&quot;143&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*Yw2XFBvuZAVXjw_drSx7Eg.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Efficient CI/CD processes requests independently; developers only worry about submitting pull requests.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;1a5a&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;8095&quot;&gt;Lesson #1: The product is a blueprint&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;618d&quot;&gt;This lesson affects the &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;continuous integration&lt;/strong&gt; portion of a CI/CD pipeline. &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Continuous integration &lt;/strong&gt;aims at merging frequent code iterations to the main development branch. The foundation of continuous integration is the concept of small, independent code changes validated by comprehensive test automation.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4641&quot;&gt;If pull requests accumulate behind sluggish validation sequences, feature branches begin to overlap in a cacophony of merge conflicts, requiring extra validation cycles.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2d9c&quot;&gt;The challenge with CI/CD for a GitOps repository is that there is no self-contained binary or package to be transferred over to a runtime environment, unlike applications. The repository has configuration files and instructions for a third-party agent to effect changes in the final medium: the infrastructure.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b520&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;If CI/CD for applications produces (virtual) bricks, CI/CD for GitOps makes blueprints.&lt;/em&gt;&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;d749&quot;&gt;&lt;img alt=&quot;Robot examines a small box coming out of a conveyor belt and sees a list of instructions that alter the make up of the infrastructure.&quot; class=&quot;graf-image&quot; data-height=&quot;422&quot; data-image-id=&quot;1*qkr_ojtwVyid2Ia8jYnYlw.png&quot; data-width=&quot;1250&quot; height=&quot;216&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*qkr_ojtwVyid2Ia8jYnYlw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;A pull request is more than its contents: it is a set of instructions for a remote agent responsible for acting on the infrastructure.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;916d&quot;&gt;Applications may be sophisticated bricks that react differently to the environment where they sit — so do real bricks — but a downloaded binary is structurally identical to any other downloaded binary.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4beb&quot;&gt;Now, contrast the certainty about the composition of that virtual brick with the confidence you may have in what you get from a folder in a GitOps repository. For simplicity, let’s assume a GitOps repository containing a few folders representing a fleet of Kubernetes clusters, with a “common” folder containing shared settings across all clusters and a folder for each cluster containing only the settings that differ from the shared settings.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e34b&quot;&gt;When someone modifies a shared setting in that “common” folder, that also changes the effective desired state for all clusters. It is not like one can validate the full extent of that change short of actually effecting the change on all these clusters, so we must settle for &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;validating &lt;em class=&quot;markup--em markup--p-em&quot;&gt;the new blueprint&lt;/em&gt; &lt;/strong&gt;in resources as similar as possible to those in a production environment, which is covered in lesson #4.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;f50e&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;ea75&quot;&gt;Lesson#2: Small, independent changes&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;afc3&quot;&gt;Small, independent changes are an often overlooked aspect of continuous integration. It is easier to break this rule while doing application development, especially when the test automation achieves a certain level of functional coverage.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;433b&quot;&gt;With GitOps, extensive changes to the repository mean multiple parts of the infrastructure changing at once, possibly asynchronously, which tends to surprise people with avoidable outages. No one likes the words “surprise” or “outage” next to a production deployment, so it is a good idea to formalize the practice of making small changes as part of the CI/CD pipeline and avoid accidentally terraforming a deployment into a whole new world.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;dc61&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Flag extensive changes. &lt;/strong&gt;All major Git providers support APIs to add various “status” messages to a Git commit, so this is the perfect place to validate whether a pull request is “small.” For example, if the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;repository design&lt;/a&gt; calls for a parent folder for each class of devices, the automation may flag pull requests containing changes to more than one class of devices.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;399c&quot;&gt;&lt;img alt=&quot;Oversized box falling off to the right of a conveyor belt, with a robot overwhelmed with its size and over 1000 work items described in the box.&quot; class=&quot;graf-image&quot; data-height=&quot;339&quot; data-image-id=&quot;1*xbsFx03Xddk6QR_KraVHxw.png&quot; data-width=&quot;1103&quot; height=&quot;197&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*xbsFx03Xddk6QR_KraVHxw.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Large pull requests can exceed the unwritten pipeline specifications, resulting in “terraforming”-like reconciliation with the target infrastructure.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8d6b&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;ba86&quot;&gt;Lesson #3: When small is&amp;nbsp;big&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;41a1&quot;&gt;Changing a few lines on a blueprint may have an outsized impact on the final product in the real world. Likewise, a few characters in a GitOps repository may trigger massive shifts in the infrastructure, so we need to extend the concept of “small, independent changes” to the impact of a change.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1b8d&quot;&gt;Continuing the previous example — a change to a folder containing shared settings for individual resources — imagine you have a compatibility-threatening configuration change request, such as upgrading Kubernetes clusters to the recent 1.22 release. This release removed support for several long-standing beta APIs, and adopters received extensive warnings and education for several months before the release about the potential disruptions to existing workloads.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f818&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Gradual rollouts. &lt;/strong&gt;While the pull request with the version change to the “common” folder is technically “small,” it probably deserves a more deliberate rollout approach, updating only a few clusters in the earlier stages of the pipeline.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f659&quot;&gt;The exact strategy for “deliberate” may vary. A simple approach may entail an initial commit to a couple of individual folders mapped to clusters in the “development” stage. It is best to look into tooling specialized in rollout strategies for larger deployments and increased productivity, such as blue-green, canaries, and feature flags.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;ed84&quot;&gt;&lt;img alt=&quot;Item falls off a conveyor belt, containing an instruction to reshape triangles into star-shape figures. Robot looking at the instructions “sweats” when realizing there are thousands of triangle-shaped items to be reshaped.&quot; class=&quot;graf-image&quot; data-height=&quot;388&quot; data-image-id=&quot;1*qDT5I3iTbT2THXGwTkt5TA.png&quot; data-width=&quot;1330&quot; height=&quot;187&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*qDT5I3iTbT2THXGwTkt5TA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Pull requests small in size may contain subtle changes that have an outsized impact on the infrastructure.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;ce3b&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;32e0&quot;&gt;Lesson #4: Unit testing is integration testing&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6821&quot;&gt;One of the cornerstones of &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;continuous delivery&lt;/strong&gt; is an extensive battery of automated tests. Good test automation covers the range of unit, integration, and system tests. With GitOps, unit testing becomes a little murkier because the resource contents are often proxies to infrastructure components. The resources also lean towards declarative approaches using “mini languages,” such as Terraform files and even the occasional DDL file for relational databases.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;aa99&quot;&gt;Testing “mini languages” in pull requests is a common dilemma in unit testing because the statements are entangled with specialized backend servers. Think relational databases, messaging servers, and other types of stateful layers. Attempting to simulate the work of these dependencies is often a losing and expensive proposition, so application developers tend to rely on the usage of mock objects and defer the vestigial gap in test coverage to later stages of the CI/CD pipeline.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0ae7&quot;&gt;When it comes to GitOps, that gap coverage gap is much broader, even if you are cleverly mimicking the technique of using mock objects with something like &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.cncf.io/online-programs/end-yaml-engineering-with-cdk8s/&quot; href=&quot;https://www.cncf.io/online-programs/end-yaml-engineering-with-cdk8s/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;cdk8s&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9c7a&quot;&gt;Closing that gap in the earliest pipeline stage is a challenging balancing act between speed and coverage. Leave too much testing out of the pull request validation, and problems escape long enough to require rework to most issues; try and validate all scenarios, and the pull requests start to pile up and collide.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c65e&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Reconciliation is for speed.&lt;/strong&gt; The effects of merging a pull request on the infrastructure tend to fall along the CRUD axis of &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;cr&lt;/strong&gt;eation, &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;u&lt;/strong&gt;pdates, and &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;d&lt;/strong&gt;eletions.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b8f8&quot;&gt;In order of speed, from faster to slower, we typically see deletion, update, and creation.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;35d7&quot;&gt;When creating new resources starts to take disproportionally longer than the other operations, it makes sense to favor reconciliation tests against a standing environment, at least in the earlier stages of the pipeline.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7770&quot;&gt;Standing environments may also bring a financial cost to the balance between speed and coverage, a common gold-plated blindspot for many technical people. I am not saying you should be counting the dollars before issuing a pull request, but whoever designs the CI/CD pipeline for a GitOps practice absolutely should be making those calculations side-by-side with the technical decisions.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;e6ad&quot;&gt;&lt;img alt=&quot;Conveyor belt with multiple items of different shapes rolling to the right. Robot rushing with a triangle-shaped item towards a set of large boxes, with one box having a triangle-shaped hole matching the item the robot is carrying.&quot; class=&quot;graf-image&quot; data-height=&quot;418&quot; data-image-id=&quot;1*e3FiNjnQVP4-RRK64CC2_A.png&quot; data-width=&quot;1415&quot; height=&quot;189&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*e3FiNjnQVP4-RRK64CC2_A.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Applying pull requests to existing environments is often faster than creating entire environments from&amp;nbsp;scratch.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7286&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;The safety of no reconciliation.&lt;/strong&gt; In this approach, any change to the repository means deleting and recreating all resources corresponding to that change.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6fdb&quot;&gt;The approach has some merit, as it cuts down test scenarios considerably and ensures a more consistent overall system state due to components effectively resetting their internal state every time their configuration changes.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ddab&quot;&gt;The drawback is that as the system scale increases to thousands of resources, one must have unwavering trust in the entire subsystem responsible for recreating thousands of resources quickly. One must also be willing to become intimately familiar with the underbelly of large-scale provisioning in most IaaS providers: API rate limits, network traffic jams due to terabytes of images floating around the private network, bootstrap bugs that only rear their heads when the network is congested, and many others.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;6a65&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;cf36&quot;&gt;Lesson #5: There is no rolling&amp;nbsp;back&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;bfe5&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;This lesson assumes the GitOps repository is versioned with branches or tags, as outlined in the &lt;/em&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@dnastacio/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; href=&quot;https://medium.com/@dnastacio/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; target=&quot;_blank&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;previous article in this series&lt;/em&gt;&lt;/a&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;.&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5abc&quot;&gt;In a multi-staged CI/CD pipeline, you have parallel environments such as “development,” “test,” and “production.” A pull request may pass validation in the early stages of the pipeline and still fail in production.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6061&quot;&gt;When a production environment has a problem, it is natural to expect people to call for a rollback, especially from outside the DevOps team. Rolling back makes a lot of sense in the abstract: if the changes broke things, then bring back the old configuration.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;15c5&quot;&gt;In the real world, however, a GitOps repository contains a mixture of imperative (scripted) and declarative statements, which means a previous commit does not ensure the system &lt;em class=&quot;markup--em markup--p-em&quot;&gt;state &lt;/em&gt;will revert to what it was before the attempt to move forward. Still, even if referencing that old commit somehow brings the system back to life, you now have a disrupted pipeline flow and two unsavory choices:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;9066&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Create a new patch.&lt;/strong&gt; Submit a change request for whatever afflicted the production system and roll it through the pipeline. All earlier stages will go from commit “N” to commit “N+1,” and the production stage will eventually make a long jump from commit “N-1” to commit “N+1”. That means the production system will have gone through different internal states than other stages, potentially increasing the differences between the stages.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;690d&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Reverse the pipeline.&lt;/strong&gt; Rollback the changes on all other pipeline stages to match the rolled back stated of the production environment. I consider this approach unthinkable as a standing practice because it is always possible that a completely unrelated pull request has already started its way through the pipeline. Even if one successfully reverses the entire pipeline back to a known baseline, there is still the unresolved matter of dealing with previously merged requests after ejecting them from the pipeline.&lt;/li&gt;&lt;/ol&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;5412&quot;&gt;&lt;img alt=&quot;Person stands on a paused conveyor belt, pushing a box to left while other items sit piled up in a messy fashion atop the conveyor belt.&quot; class=&quot;graf-image&quot; data-height=&quot;357&quot; data-image-id=&quot;1*vHzwaR9I7uRHooTPhy3R_g.png&quot; data-width=&quot;1324&quot; height=&quot;173&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*vHzwaR9I7uRHooTPhy3R_g.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;When developers and operations managers need to step in to deal with a troubled pull request, the flow of activities comes to a halt, and there is uncertainty on how to progress.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b917&quot;&gt;Given enough brainpower in studying the failing pull request and wizard-like ability with the Git command line, a rollback is often possible but rarely cost-effective, so it is crucial to keep a couple of design principles in mind to minimize those occurrences:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;9d5a&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Small and independent&lt;/strong&gt;. I mentioned it before, but worth repeating it. Keeping pull requests small in size and impact on the infrastructure means it is easier to entertain a new pull request to undo the breaking change than considering a rollback across pipeline stages.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;3e8f&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;One pull request at a time&lt;/strong&gt;. Assuming the volume of changes allows for it, implement a policy of allowing a single pull request to roll across the pipeline. The pipeline can queue the processing of another pull request until it promotes the current pull request to production.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;24fc&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Treat rollbacks as exceptions.&lt;/strong&gt; Unless the infrastructure supports reliable downgrades to the previous version, do not entertain rollbacks as a regular, automated process. If the infrastructure has complex internal states or, worse, databases, rollbacks rarely bring the system back to health.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b01d&quot;&gt;Ultimately, it may be impossible to completely rule out the chance of a rollback in a production environment, but following these tips can minimize their occurrence and impact&lt;em class=&quot;markup--em markup--p-em&quot;&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;ca6d&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;bec6&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6bcb&quot;&gt;CI/CD practices for application development are well-suited for GitOps repositories, but the pipelines produce very different artifacts from applications.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b991&quot;&gt;GitOps repositories contain blueprints that remote agents can follow while building or reconfiguring infrastructure. Changes have ramified and widespread implications even for small changes, so it is essential for pipeline designers to carefully consider the goals for developer productivity and costs to the organization.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;965e&quot;&gt;For developers, GitOps requires renewed attention to the CI/CD principles of keeping changes small in size, realizing that “small” also extends to anticipating the impact of changes in the underlying infrastructure and adjusting pull requests to reduce that impact where possible.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ed13&quot;&gt;These lessons helped me minimize the number of manual interventions to our GitOps pipeline and, more importantly, smooth out the flow of activities and the amount of rework around them. While some of the lessons may be more of a journey than concrete recipes, I think they are universal enough to help practitioners at various stages of adoption.&lt;/p&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;a762&quot;&gt;References&lt;/h3&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;fa34&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment&quot; href=&quot;https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Continuous integration vs. continuous delivery vs. continuous deployment&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;cae4&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.cncf.io/blog/2020/06/29/infrastructure-as-code-a-non-boring-guide-for-the-clueless/&quot; href=&quot;https://www.cncf.io/blog/2020/06/29/infrastructure-as-code-a-non-boring-guide-for-the-clueless/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Infrastructure as code: A non-boring guide for the clueless&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;63a1&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;The GitOps Files — Repository design&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;e458&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.ibm.com/cloud/blog/ci-cd-pipeline&quot; href=&quot;https://www.ibm.com/cloud/blog/ci-cd-pipeline&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;A practical guide to the continuous integration/continuous delivery (CI/CD) pipeline&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;e690&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://medium.com/containers-101/argo-rollouts-the-kubernetes-progressive-delivery-controller-reaches-1-0-milestone-e0d8e610e9a5&quot; href=&quot;https://medium.com/containers-101/argo-rollouts-the-kubernetes-progressive-delivery-controller-reaches-1-0-milestone-e0d8e610e9a5&quot; target=&quot;_blank&quot;&gt;Argo Rollouts, the Kubernetes Progressive Delivery Controller, Reaches 1.0 Milestone&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;383f&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://docs.github.com/en/rest/reference/repos#statuses&quot; href=&quot;https://docs.github.com/en/rest/reference/repos#statuses&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitHub Status API&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/5897024091103445640/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/03/effective-cicd-strategies-for-gitops.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5897024091103445640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5897024091103445640'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/03/effective-cicd-strategies-for-gitops.html' title='Effective CI/CD strategies for GitOps'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-5103839860437537983</id><published>2022-02-28T20:30:00.004-08:00</published><updated>2022-04-19T11:07:12.959-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="automation"/><category scheme="http://www.blogger.com/atom/ns#" term="cicd"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="gitops"/><category scheme="http://www.blogger.com/atom/ns#" term="k8s"/><title type='text'>Design strategies for GitOps repositories</title><content type='html'>&lt;p&gt;(I originally &lt;a href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5?source=friends_link&amp;amp;sk=f388bc2a35c58be1abcd6bd898bb65bf&quot; target=&quot;_blank&quot;&gt;posted this article on Medium.com&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&amp;nbsp;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;(This story is the foundation of my other story, &lt;/em&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d?source=friends_link&amp;amp;sk=3c750a9c6ab5ad126294f7b845197525&quot; href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d?source=friends_link&amp;amp;sk=3c750a9c6ab5ad126294f7b845197525&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;designing CI/CD pipelines for GitOps&lt;/em&gt;&lt;/a&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;.)&lt;/em&gt;&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;9be6&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;92b0&quot;&gt;Spend a few hours in your newly established GitOps practice, and you soon realize you need to decide how to represent your infrastructure as folders.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7cbd&quot;&gt;On the one hand, infrastructure is rich in concepts and relationships, spread over physical and logical entities. On the other hand, Git repositories have only a few building blocks to represent that knowledge: branches, tags, a folder tree, and files inside the folders.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;49f2&quot;&gt;&lt;img alt=&quot;Left portion of picture is a network topology of a Kubernetes cluster with 3 notes, with each node backed by a virtual machine. The right-side shows a tentative mapping of that topology to a folder structure.&quot; class=&quot;graf-image&quot; data-height=&quot;583&quot; data-image-id=&quot;1*6tLp2GrvgJPf5HcmKHthgQ.png&quot; data-is-featured=&quot;true&quot; data-width=&quot;2224&quot; height=&quot;168&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*6tLp2GrvgJPf5HcmKHthgQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Mapping a semantic network to a folder structure is not always straightforward.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;094a&quot;&gt;Now you have a classic mapping problem. Should folders be organized by device class? By pipeline stage? Maybe dedicate a folder to each specific device? How about relationships?&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fe85&quot;&gt;This article lists the core lessons I learned while establishing a GitOps practice for deploying and managing Kubernetes (OpenShift) clusters running software stacks with thousands of containers.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;be73&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;af0c&quot;&gt;Lesson #1: Beware the&amp;nbsp;topology&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7c97&quot;&gt;Do not spend too much time developing an elaborate folder structure resembling the structure of the deployment environment. Anything over a certain depth makes navigation cumbersome, documentation more complicated, and explanations longer.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b467&quot;&gt;My magic number is three levels. Your number may vary, but the challenge past that number is that folder trees are relatively narrow and rigid structures without the means to add attributes to folders or relationships. While one may assign semantics to levels in the tree, those semantics are not visible in a file explorer and need to be written down somewhere else.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d48f&quot;&gt;As a result, “tall” trees not only result in dissonant changes of themes across folder levels, these external semantics do not hold up well as the system evolves. For instance, take the somewhat long navigation path below as a concrete representation of how folders are organized inside a Git repository:&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c737&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;/production/us-east/kubernetes/omnicorp-cluster/operators/elastic&lt;/em&gt;&lt;/p&gt;&lt;figure class=&quot;graf graf--figure graf--startsWithDoubleQuote&quot; name=&quot;13e1&quot;&gt;&lt;img alt=&quot;Figure of system administrator overwhelmed with a folder structure that is over 6 levels deep, containing a deployment environment, IaaS region, infrastructure type, k8s clusters, services, and others.&quot; class=&quot;graf-image&quot; data-height=&quot;529&quot; data-image-id=&quot;1*D-1M5BSB2zZU39GXjsX6EA.png&quot; data-width=&quot;1532&quot; height=&quot;221&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*D-1M5BSB2zZU39GXjsX6EA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;“Tall” repository trees can make repository navigation a constant&amp;nbsp;chore.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ec9e&quot;&gt;Such implicit folder structure may feel like a sensible containment tree, but what if you need a new Kubernetes cluster deployed with redundant workers across multiple regions? Now you can no longer respect the semantics for the second-level folders because they represent a single region containing the cluster workers.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;82ae&quot;&gt;At that point, you have two options:&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5396&quot;&gt;1. Adding a “multi-region” folder under “production.” The second level of folders in the tree would have a conceptual mixture of specific regions in the infrastructure provider and, disconcertingly, a logical representation that would not match a particular region.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e702&quot;&gt;2. You struggle with the cognitive dissonance in option “1” for a few minutes and consider removing the concept of regions from the folder structure, first ensuring that there are no region-specific settings for the clusters. Once you finally remove the concept of regions from the tree structure, you start wondering why you added it in the first place.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;11fb&quot;&gt;The insidious aspect of leaning towards topology mappings is that they initially &lt;em class=&quot;markup--em markup--p-em&quot;&gt;feel&lt;/em&gt; right, even when not strictly necessary or valuable. Therefore, it is important to question every new extra layer proposed to the folder structure, asking yourself whether the new layer will inform considerations and decisions in the workflows around the repository.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;67cc&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;62f9&quot;&gt;Lesson #2: Versioning with branches and&amp;nbsp;tags&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e024&quot;&gt;All changes must eventually converge to the main branch, but iterations should be versioned using branches and tags in the repository.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;277a&quot;&gt;Branches and tags are the only extra structural dimension for the tree-based organization of the folders in a Git repository. I use the word “structural” because one can create new dimensions through external conventions, which incurs many of the pitfalls listed in the previous section.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5546&quot;&gt;Git branches and tags are essential to support parallel deployments of the same repository across different deployment zones. That ability to support parallel deployments is needed when validating repository changes across different stages of a deployment pipeline.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5452&quot;&gt;As you work with branches and tags, it is often beneficial to adopt &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;semantic versioning &lt;/strong&gt;(&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://semver.org/&quot; href=&quot;https://semver.org/&quot; rel=&quot;nofollow noopener noopener noopener noopener noopener noopener&quot; target=&quot;_blank&quot;&gt;https://semver.org/&lt;/a&gt;) as the naming strategy. Semantic versioning rules are sensible and well-documented, making it easier for users of a repository to identify more recent versions and quantify the differences between branches as major, minor, or simple patches.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;37f8&quot;&gt;I have seen teams implement simplified versions of semantic versioning without the “major” field, reasoning that “major” entails backward-incompatible changes and that there should never be such a thing in a continuous deployment pipeline.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;b4d5&quot;&gt;&lt;img alt=&quot;Developer submitting version 1.1.0 to the GitOps repository on a pipeline with “dev”, “test”, “stage”, and “prod” stages. The testing is currently happening in the “test” stage and the remaining stages are still at version 1.0.9.&quot; class=&quot;graf-image&quot; data-height=&quot;424&quot; data-image-id=&quot;1*sSbMc4k4v2clQOU3Lem2BQ.png&quot; data-width=&quot;1170&quot; height=&quot;232&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*sSbMc4k4v2clQOU3Lem2BQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;A new candidate patch branch is being rolled across the deployment pipeline.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;14d3&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Feature branches are ok&lt;/strong&gt;. I am excepting the usage of short-lived “feature” branches from this lesson. The use of these branches is undisputed since these are the branches created temporarily to support reviews and validation of pull requests. Merged branches add up quickly and start to become a source of clutter and confusion, so I recommend turning on the respective Git provider setting to delete branches immediately after being merged to the target branch.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7623&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Not all differences are created equal&lt;/strong&gt;. A core design principle for a continuous deployment pipeline is minimizing differences between stages because fewer differences increase the chances that a change works in the next pipeline.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;37d2&quot;&gt;Before discussing solutions, let’s qualify those differences:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;c567&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Intrinsic differences&lt;/strong&gt;. These are long-term structural differences between different environments, such as a VLAN identifier, different numbers of VMs, or different cloud regions.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;a722&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Versioning differences&lt;/strong&gt;. These are the expected transient differences while changes are validated in the previous pipeline stage, such as image URLs for the containers used in the product or versions of micro-services comprising the whole product.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;80d1&quot;&gt;Intrinsic differences should reside in files named as specific to a pipeline stage, such as “values-production.yaml” or “values-us-south.yaml”.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8c8f&quot;&gt;Versioning differences should not go in files named or otherwise marked as specific to an environment. There may be rare exceptions to that rule, but as Ford Prefect once said: &lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Even if you prove it to me, I won’t believe it.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4468&quot;&gt;With that combination of folder structure, file contents, and branching, let’s walk through the two typical workflows: one that should affect all deployments and one that should only affect a single environment:&lt;/p&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;ffdd&quot;&gt;Modifying all deployments&lt;/h4&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;558e&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;The genesis. &lt;/strong&gt;Developer clones the repository and checkout the “main” branch. Usually, this should be the default branch for the repository.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;7222&quot;&gt;The developer creates a new branch named “feature-1”, makes local changes to the cloned repository, commits the changes, and pushes the new “feature-1” branch to the remote Git repository at the Git Provider.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;7d90&quot;&gt;The developer submits a pull request for “feature-1” into the “main” branch (For GitLab users, that would be a merge request.)&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;bec9&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Trying times ahead.&lt;/strong&gt; The Git provider issues an event about the pull request to an automated process — owned by the repository owners — responsible for applying the change to the “dev” environment.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f99e&quot;&gt;The automated process applies the changes in “feature-1” to the development environment and starts the validation tests.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;4c7f&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;A new branch is born.&lt;/strong&gt; Assuming the validation tests pass, the new “feature-1” is considered good enough to be merged back into “main,” and that new version of “main” with the changes becomes the basis of a new versioned branched. Note: An automated process cannot guess the correct name for the new branch in a semantic versioning scheme, so it is helpful to allow the author to add that type of clue in the text of the pull request.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;36c7&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Failure is an option&lt;/strong&gt;. It is still possible that validation in the next pipeline stages uncovers a problem with the new branch resulting in it being sidelined as failed, stopping its progression across the pipeline.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;880e&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;Retreating is not an option&lt;/strong&gt;. While there are proponents of a rollback strategy for the stages containing a failed branch, accept that rolling forward is the better approach (A topic I covered in a &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d&quot; href=&quot;https://dnastacio.medium.com/the-gitops-files-ci-cd-bricks-and-blueprints-fcfdb5b3e34d&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;separate article about CI/CD pipelines for GitOps&lt;/a&gt;.) In the “roll forward” strategy, a new issue is automatically created, and the team works on a new patch that addresses the issue. Fixing this situation takes precedence over any other modification, and the pipeline is closed for further changes.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;2066&quot;&gt;&lt;strong class=&quot;markup--strong markup--li-strong&quot;&gt;If it doesn’t fail, keep it going.&lt;/strong&gt; With the pull request merged into “main,” that request is closed automatically, and an automated process starts to deploy the changes to the next stage of the pipeline.&lt;/li&gt;&lt;/ol&gt;&lt;h4 class=&quot;graf graf--h4&quot; name=&quot;cede&quot;&gt;Modifying a single environment&lt;/h4&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a155&quot;&gt;If environment-specific folders and files are isolated to small corners of the repository, this scenario is virtually identical to the modification of all environments.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5190&quot;&gt;There is room for some optimizations, like skipping slower or expensive tests in environments other than the one being modified. However, one must carefully manage the costs of developing these unique paths and weigh them against the volume of changes to single environments.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;82aa&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;No branch per environment&lt;/strong&gt;. I must put a strong emphasis on the word “versioning” in the title of this lesson. “Beware the topology” still applies, and trying to create a branch per deployment environment is riddled with pitfalls. &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/containers-101/stop-using-branches-for-deploying-to-different-gitops-environments-7111d0632402&quot; href=&quot;https://medium.com/containers-101/stop-using-branches-for-deploying-to-different-gitops-environments-7111d0632402&quot; target=&quot;_blank&quot;&gt;This article&lt;/a&gt; covers the main problems in great detail, so I will not revisit them here.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;bbd7&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;682d&quot;&gt;Lesson #3: Beware the&amp;nbsp;Monorepo&lt;/h3&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;c9e8&quot;&gt;“Monorepo” is a strategy where the entire infrastructure is represented in a single Git repository, such as applications, services, and infrastructure.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e59a&quot;&gt;I consider this approach useful for demonstrations and class material, where the content is managed by a few people and applied to non-production, short-lived environments.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;14b9&quot;&gt;&lt;img class=&quot;graf-image&quot; data-height=&quot;1054&quot; data-image-id=&quot;1*2_awV12-kB35oaCWjH1PTQ.png&quot; data-width=&quot;2234&quot; height=&quot;302&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*2_awV12-kB35oaCWjH1PTQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;Monorepo GitOps repo with multiple disciplines, from applications to infrastructure&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f521&quot;&gt;For production environments, a GitOps practice is likely using some form of managed or self-hosted Git provider, such as GitHub, GitLab, or BitBucket (Note that GitLab is the only provider to open-source its code and allow self-hosting.) These Git providers have a few architectural constraints limiting the usage of monorepos,&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ef5c&quot;&gt;Managed Git providers attach extra configuration, eventing, workflows, and access control to Git repositories. As your organization grows, disciplines like application development and infrastructure tend to become more specialized, with that specialization manifesting itself in at least two relevant dimensions:&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5c90&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Workflows&lt;/strong&gt;. Git providers support automated handlers for events in the repository, such as creating new branches, creating new commits, or requesting a code review.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;edf6&quot;&gt;Handling the creation of a new commit on an “infrastructure” folder is likely to require significantly different validation strategies when compared to handling a change to the “apps” folder. When all folders are in the same repository, every change to any of the folders generates a new event, leaving it up to the automated handler to reroute the event.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1fcc&quot;&gt;Writing and maintaining routing event mechanisms can be fun in their own right but can also become avoidable distractions in your GitOps practice.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;db62&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Work management and access control&lt;/strong&gt;. With different workflows come specialized sets of people. Someone who understands the releases of the shopping cart application may not necessarily be the same person who can vet a merge request to assign virtual machines to a load balancer.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;609d&quot;&gt;Git providers do not offer access control per folder, file, label, or branch, so organization members end up having access to everything in that repository. Update on 4/16: &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@joebowbeer&quot; href=&quot;https://medium.com/@joebowbeer&quot; target=&quot;_blank&quot;&gt;Joe Bowbeer&lt;/a&gt; noted in the comments section that GitHub’s &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners&quot; href=&quot;https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“code owners”&lt;/a&gt; feature could ensure a minimum set of reviewers based on file names in the pull request.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8d1a&quot;&gt;Skipping past eventual &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/why-you-should-avoid-sealed-secrets-in-your-gitops-deployment-e50131d360dd&quot; href=&quot;https://dnastacio.medium.com/why-you-should-avoid-sealed-secrets-in-your-gitops-deployment-e50131d360dd&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;security concerns around Sealed Secrets&lt;/a&gt;, repository members may still be distracted by extraneous churn and notifications. Over time, as the volume of uninteresting notifications increases, you start to notice some undesirable outcomes: Either people muscle through the noise or people turn off the notifications. Muscling through the noise incurs individual productivity penalties while turning off notifications slows down the flow of activities.&lt;/p&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;4294&quot;&gt;Lesson #4: The workflow rule. Workflows rule.&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;de54&quot;&gt;This lesson extends the previous one: if monorepos have limited application, it follows that one should always have multiple repos, but which ones? While we examine this lesson, it is also important to note that an excessive proliferation of repositories also introduces new costs in managing all these repositories, keeping tabs on access control lists, webhooks, access tokens, and many others.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b907&quot;&gt;Even as Git providers support some consolidation of those settings in a parent “organization” containing multiple projects, that means sidelining people and resources to own the shared responsibility for those settings.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;993c&quot;&gt;Lesson #1 shows how topology or containment mappings may not be the best organizing principles, so it is time to let folder structures take a back seat and remember that Git providers organize workflows around repositories.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;9120&quot;&gt;&lt;img alt=&quot;People and automation looking at Git repository and collaborating to update a deployment environment.&quot; class=&quot;graf-image&quot; data-height=&quot;550&quot; data-image-id=&quot;1*EI-q0Teok9b28oYs-NZVDA.png&quot; data-width=&quot;1380&quot; height=&quot;255&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*EI-q0Teok9b28oYs-NZVDA.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot;&gt;People and processes shape the Git repository structure, not the deployment topology.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4f61&quot;&gt;The rule of thumb to define boundaries between repositories is to look at the Git provider settings and find the overlaps between people and automated processes. If people and processes overlap entirely, then a single repository is likely sufficient for that team.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9ae3&quot;&gt;If people or processes differ, it is time to consider another repository, possibly under the same Git provider “organization.” An “organization” works as a shared container for multiple repositories. It is a good place to share settings across repositories, such as a well-designed continuous integration pipeline for building containers, configuration linters, etc.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;da28&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;b717&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3057&quot;&gt;Working with deployment environments and Git repositories is a constant exercise in mapping complex topologies to simpler structures. While a deployment structure may seem like a tempting starting point due to the team’s familiarity, &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;topologies tend to be a misleading organizing principle&lt;/strong&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6dc9&quot;&gt;Many mapping rules may be costly to be established, only to fail a moment later when you try to represent new topology nuances. &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Organizing repositories around workflows and people &lt;/strong&gt;keeps the mapping exercises focused and reduces friction between day-to-day activities and folders.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6047&quot;&gt;As the practice grows, &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;use branches and tags to keep your deployment pipelines moving forward&lt;/strong&gt;. As processes mature, &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;promote common automated workflows to the organization level&lt;/strong&gt; while keeping repositories isolated to minimize distractions in manual flows (e.g., reviews and approvals.)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0b04&quot;&gt;I hope these lessons are helpful in new and established deployments, and I would like to read your comments (and links) on the topic. Now, let’s deploy some systems.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;bc32&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;0550&quot;&gt;References&lt;/h3&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;8730&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.youtube.com/watch?v=HDg5vh97zmI&quot; href=&quot;https://www.youtube.com/watch?v=HDg5vh97zmI&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;GitOps Guide to the Galaxy (Ep 23): Directory structure battles&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;b76c&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://fluxcd.io/docs/guides/repository-structure/&quot; href=&quot;https://fluxcd.io/docs/guides/repository-structure/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Ways of structuring your repositories&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;fb8f&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://copyconstruct.medium.com/testing-microservices-the-sane-way-9bb31d158c16&quot; href=&quot;https://copyconstruct.medium.com/testing-microservices-the-sane-way-9bb31d158c16&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Testing microservices the sane way&lt;/a&gt;&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;d8d5&quot;&gt;&lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://medium.com/containers-101/stop-using-branches-for-deploying-to-different-gitops-environments-7111d0632402&quot; href=&quot;https://medium.com/containers-101/stop-using-branches-for-deploying-to-different-gitops-environments-7111d0632402&quot; target=&quot;_blank&quot;&gt;Stop Using Branches for Deploying to Different GitOps Environments&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/5103839860437537983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/02/design-strategies-for-gitops.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5103839860437537983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5103839860437537983'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/02/design-strategies-for-gitops.html' title='Design strategies for GitOps repositories'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-5269871471903439054</id><published>2022-02-11T10:46:00.004-08:00</published><updated>2022-05-12T08:59:31.564-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="argocd"/><category scheme="http://www.blogger.com/atom/ns#" term="gitops"/><category scheme="http://www.blogger.com/atom/ns#" term="secrets"/><category scheme="http://www.blogger.com/atom/ns#" term="vault"/><title type='text'>Why you should avoid Sealed Secrets in your GitOps deployment</title><content type='html'>&lt;p&gt;(I originally posted this article on &lt;a href=&quot;https://dnastacio.medium.com/why-you-should-avoid-sealed-secrets-in-your-gitops-deployment-e50131d360dd?source=friends_link&amp;amp;sk=ccfe406e91e3b03c3893bc492082f1c3&quot;&gt;medium.com&lt;/a&gt;)&lt;br /&gt;&amp;nbsp;&lt;/p&gt;&lt;section class=&quot;section section--body&quot; name=&quot;19d7&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7104&quot;&gt;GitOps is the practice of representing system configuration in a Git repository and then using Git workflows to manage changes to that configuration and updates to the system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;92f0&quot;&gt;That process of representing system configuration in a repository is initially straightforward, seeding configuration files, copying declarative requests from product documentation, and maybe even the occasional scripted sequence.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9c4d&quot;&gt;At first, you feel progress is inevitable, and success awaits a few commits around the corner, then you hit the ultimate GitOps foil: secrets.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9c4d&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8aa6&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7b9c&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7b9c&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Why plain secrets are bad&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;944d&quot;&gt;While it may be evident that placing plain credentials on a Git repository is not the best idea, it is still worth spelling out why it is problematic, lest someone feels it may be an acceptable compromise when using a private repository:&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ca75&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;The people who work with the GitOps repository may not be the same people authorized to manage the target environments.&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f413&quot;&gt;Let’s say you are the approver of a pull request and need the resident network expert to review changes related to the firewall. Unaware that credentials are stored in plain text in the repository, you ask the repository manager to add that expert to the list of users. Suddenly, the network expert has access to a customer database full of private data. If that person is not cleared for that level of access, you are looking at all sorts of paperwork and remediation procedures to rotate and deploy new credentials.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;184e&quot;&gt;Now, let’s assume a better scenario, where you are aware of the credentials in the repository, thus avoiding the accidental disclosure: now you need to go outside the pull request workflow to involve that person in the review process.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7e7c&quot;&gt;When the better scenario is inefficiency and the worst scenario is akin to juggling knives blindfolded, you know it is time to move on to better practices.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;e094&quot;&gt;&lt;img alt=&quot;Administrator in panic with password in the clear in a Git repository.&quot; class=&quot;graf-image&quot; data-height=&quot;367&quot; data-image-id=&quot;1*pI_YQCb9WKNpJmiSxPKBtw.png&quot; data-width=&quot;514&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*pI_YQCb9WKNpJmiSxPKBtw.png&quot; /&gt;&lt;/figure&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;e094&quot;&gt;&lt;br /&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;313c&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8030&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;A sealed solution&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b1ae&quot;&gt;The idea of a sealed secret in GitOps is to encrypt secrets before adding them to the repository, sharing the private encryption key with those who need to use those secrets. Typically, these encryption keys are placed on the target system and used by a local agent to decrypt the credentials and place them wherever they need to be in the target environment.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9b31&quot;&gt;This technique allows people to work with the repository without the risk of accidentally disclosing credentials, and that is an improvement over storing credentials in plain sight.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d604&quot;&gt;That approach is clever, and I was quite fond of it at the beginning of my journey into GitOps. The initial setup is somewhat easy, the repositories are not widely used on a daily basis yet, and it is easy to find others at that same stage of adoption vouching for the approach, so you can also find support in the community.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1ebc&quot;&gt;Getting past the initial stage and going into larger and more permanent deployments, that simplicity gave way to limitations and risks, and I abandoned the practice altogether. In the next sections, I highlight the main reasons you probably should abandon it too.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1ebc&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;a01c&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;27b2&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;27b2&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Reason #1&lt;/strong&gt;: The keys to which environment?&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;837b&quot;&gt;Let’s say you have a deployment pipeline with a progression of “dev,” “test,” “stage,” and “production” environments. Each environment will be running the same software, but if you use good SecOps practices, they will use different sets of credentials.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5e60&quot;&gt;Some GitOps repositories are designed to have one subtree per target environment, while others are designed with a single parameterized tree deployed across different environments.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0d0a&quot;&gt;In the case of a folder tree per target environment, the git repository must have separate locations for the keys for each environment. When you work with the ubiquitous presence of Kubernetes clusters in the enterprise, you will be dealing with individual “Secret” resources spread across multiple namespaces, making the sprawl of folders and files unavoidable.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ec5b&quot;&gt;If we look at parameterized trees, then the situation becomes a little better, with all secrets for each environment getting concentrated into a single file per environment.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9d4a&quot;&gt;Regardless of &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; href=&quot;https://dnastacio.medium.com/gitops-repositories-the-right-way-part-1-mapping-strategies-6409dff758b5&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;how you design the GitOps repository&lt;/a&gt;, using sealed secrets generates more folders and files, which increases the amount of information people need to absorb, and the amount of artifacts the delivery pipelines need to handle.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9d4a&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;c779&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e3c5&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;e3c5&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Reason #2&lt;/strong&gt;: The secrets are&amp;nbsp;… &lt;em class=&quot;markup--em markup--p-em&quot;&gt;right there.&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;03e2&quot;&gt;Yes, they are encrypted, and it takes an encryption key to get to the actual credentials, but they are still in the hands of potentially bad actors. Imagine telling someone how their database credentials are all visible to the world and then proceeding to dissuade their anxiety by explaining how the bad actors still don’t have the key.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d538&quot;&gt;You may chime in the comments section and explain the technical reason why this is an unfounded fear, but anyone who works in security will tell you that the psychological aspect is also part of making customers feel safe with their choices.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure&quot; name=&quot;8a37&quot;&gt;&lt;img alt=&quot;Drawing of the Excalibur sword on the stone.&quot; class=&quot;graf-image&quot; data-height=&quot;772&quot; data-image-id=&quot;1*0RBtAzmZkw7cvFlAFYYBDQ.png&quot; data-is-featured=&quot;true&quot; data-width=&quot;1266&quot; height=&quot;390&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*0RBtAzmZkw7cvFlAFYYBDQ.png&quot; title=&quot;Sealed secrets follow an “Excalibur” approach, where anyone can access the (encoded) secrets but only privileged users can decode them.&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot; style=&quot;text-align: center;&quot;&gt;Sealed secrets follow an “Excalibur” approach, where anyone can access the (encoded) secrets but only privileged users can decode&amp;nbsp;them.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;0ef5&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f419&quot;&gt;On the more technical side, I had people argue that having sealed secrets in the open is no different than using public key pairs to encrypt traffic, but those are asymmetric key pairs where you &lt;em class=&quot;markup--em markup--p-em&quot;&gt;never&lt;/em&gt; have the private key out in public, encrypted, or otherwise.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6040&quot;&gt;Lastly, while the secret itself is encrypted, the metadata around them isn’t. Bad actors can exploit committer information to seed social engineering exploits, infer the rotation policies for the infrastructure components, determine whether secrets are reused across environments, and gather many other clues that can aid attacks against the target environment.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;db5b&quot;&gt;Retreating from all lines of defense against cyber attacks and pinning all hopes on defending a single point of failure is a terrible starting point for a secure system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;db5b&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;7820&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d395&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d395&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Reason #3&lt;/strong&gt;: The key to secure all keys is still a key.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;87f6&quot;&gt;The lifecycle of secrets in the repository may differ depending on what they are securing. A database credential may expire every 30 days, while a cluster credential may expire every 60 days.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;64fb&quot;&gt;What about the master encryption key for the sealed secrets themselves? Security policies will eventually force you to rotate that master key, which will require a separate process to redistribute the new key securely to all target environments.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b1c4&quot;&gt;But wait! Not having a separate process to distribute keys to target environments was the reason you chose to seal secrets in the Git repository in the first place. One may argue handling one master secret is better than handling multiple secrets, but the cost of managing one key or multiple keys is virtually the same, with the added challenge of managing the sealed secrets yourself and still needing a password manager of some sort to secure and distribute the master keys.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b1c4&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;2a3f&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ef9a&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ef9a&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Reason #4&lt;/strong&gt;: There are better solutions.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3954&quot;&gt;Git repositories were not designed with key management in mind. They have no support for key rotation, no support for serving secrets as symbolic references, no way to perform usage audits, no support for different levels of access to administrators, and so on.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5982&quot;&gt;A key management solution is designed to address all these requirements, reduce the surface area for potential leaks, and offer mitigation paths in case a key is ever compromised.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9f1d&quot;&gt;That reduction of surface area is especially important, because you cannot accidentally disclose or lose a key if it never leaves the system. As one example, in the world of Kubernetes, clusters are invariably colocated in a service plane that contains multiple key management solutions. It is common for IaaS providers to offer backend integration between services where key values never have to leave the environment.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;bf65&quot;&gt;Sticking with the example of Kubernetes, where you are likely to be using ArgoCD or Flux for your GitOps practices, they currently lack native integration with key management services, but they expose extension points to achieve that integration. For instance, the &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/secret-management/&quot; href=&quot;https://argo-cd.readthedocs.io/en/stable/operator-manual/secret-management/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;ArgoCD documentation&lt;/a&gt; says, &lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Argo CD is un-opinionated about how secrets are managed”&lt;/em&gt;, but then proceeds to offer a long list of solutions to integrate with dedicated services.&lt;/p&gt;&lt;figure class=&quot;graf graf--figure graf--startsWithDoubleQuote&quot; name=&quot;e0a2&quot;&gt;&lt;img alt=&quot;Robot substituting symbolic key name with actual value from a key vault and applying resulting resources in a data center.&quot; class=&quot;graf-image&quot; data-height=&quot;549&quot; data-image-id=&quot;1*Sui_nI1xPq52OpUy3pk1YQ.png&quot; data-width=&quot;1346&quot; height=&quot;261&quot; src=&quot;https://cdn-images-1.medium.com/max/1440/1*Sui_nI1xPq52OpUy3pk1YQ.png&quot; width=&quot;640&quot; /&gt;&lt;figcaption class=&quot;imageCaption&quot; style=&quot;text-align: center;&quot;&gt;“Late binding” of secret names to secret values at deployment time.&lt;/figcaption&gt;&lt;/figure&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a6f7&quot;&gt;A more promising approach is getting started through &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://external-secrets.io/&quot; href=&quot;https://external-secrets.io/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;“External Secrets Operator” project&lt;/a&gt;, which synchronizes secrets from various key management services into local secrets in a Kubernetes cluster (credit to my colleague &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://csantanapr.medium.com/&quot; href=&quot;https://csantanapr.medium.com/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Carlos Santana&lt;/a&gt; for that reference.)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;34fb&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@thomasboerger&quot; href=&quot;https://medium.com/@thomasboerger&quot; target=&quot;_blank&quot;&gt;Thomas Boerger&lt;/a&gt; chimed in the comments section about another alternative to sealed secrets: the usage of &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://dev.to/camptocamp-ops/argo-cd-secrets-management-using-sops-1eke&quot; href=&quot;https://dev.to/camptocamp-ops/argo-cd-secrets-management-using-sops-1eke&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;SOPS&lt;/a&gt; with Flux and Argo.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;34fb&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;f3be&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3572&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3572&quot;&gt;&lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c06b&quot;&gt;There may be valid reasons to use sealed secrets. Still, I have yet to see one framed in a positive light beyond sealed secrets being “good enough”, which implies they are cheaper to deploy than a proper key management solution. I rarely see the discussion get into the considerations of everything else involved in handling those secrets.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2b13&quot;&gt;I don’t doubt the engineering prowess of those setting out to mimic a key management service with text files in a code repo, but I question the cost-effectiveness of those approaches. The DIY crowd must resort to a combination of placing files in the git repo, mapping out key rotation cycles to git pull requests, and instrumenting continuous deployment pipelines with decryption keys to parse the repo’s contents. And if you are asking how to manage those master keys, you may find yourself in a constant cycle of coming up with &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://medium.com/@ismailyenigul/take-backup-of-all-sealed-secrets-keys-or-re-encrypt-regularly-297367b3443&quot; href=&quot;https://medium.com/@ismailyenigul/take-backup-of-all-sealed-secrets-keys-or-re-encrypt-regularly-297367b3443&quot; target=&quot;_blank&quot;&gt;creative ways of making Git act as a key management service&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3ad4&quot;&gt;One can always argue in favor of a build-as-we-grow approach, but that would position sealed secrets as a stepping stone towards using a key management service, and that is not the case. Trying to “grow out” of using sealed secrets means changes to the GitOps backend of choice and re-training operations people to completely change how they handle credentials. There is no natural progression, just paying twice for the same results.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d263&quot;&gt;Eschew sealed secrets, start your GitOps practice right, and use a managed key service.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/5269871471903439054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/02/why-you-should-avoid-sealed-secrets-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5269871471903439054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5269871471903439054'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/02/why-you-should-avoid-sealed-secrets-in.html' title='Why you should avoid Sealed Secrets in your GitOps deployment'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Raleigh, NC, USA</georss:featurename><georss:point>35.7795897 -78.6381787</georss:point><georss:box>7.469355863821157 -113.7944287 64.089823536178841 -43.4819287</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-2554083479205097140</id><published>2022-01-05T18:38:00.023-08:00</published><updated>2022-10-21T19:53:47.709-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="availability"/><category scheme="http://www.blogger.com/atom/ns#" term="container-probes"/><category scheme="http://www.blogger.com/atom/ns#" term="containers"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="modernization"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="probes"/><title type='text'>The art and science of probing a Kubernetes container, part 3: Metrics and PromQL queries.</title><content type='html'>&lt;p&gt;I wrote about using &lt;a href=&quot;https://sourcepatch.blogspot.com/2021/12/6-kubectl-queries-for-validating.html&quot; target=&quot;_blank&quot;&gt;the &lt;span style=&quot;font-family: courier;&quot;&gt;kubectl&lt;/span&gt; command-line interface to troubleshooting&lt;/a&gt;&amp;nbsp;problems with container probes as part of the series&amp;nbsp;&lt;a href=&quot;https://sourcepatch.blogspot.com/2021/12/the-art-and-science-of-probing.html&quot; target=&quot;_blank&quot;&gt;&quot;The art and science of probing a Kubernetes container.&quot;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;That command-line interface approach produces quick assessments, but those assessments&amp;nbsp;are constrained to the present state of the containers. If you want more insight into how that state evolved and how it relates to other events in the cluster, it is time to enter the observability realm and start querying&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/docs/concepts/cluster-administration/system-metrics/&quot; target=&quot;_blank&quot;&gt;Kubernetes metrics&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;A &lt;a href=&quot;https://prometheus.io/&quot; target=&quot;_blank&quot;&gt;Prometheus&lt;/a&gt; server is the most common platform for storing and querying these metrics, so this blog assumes that you have Prometheus installed in the cluster and that you can execute&amp;nbsp;&lt;a href=&quot;https://prometheus.io/docs/prometheus/latest/querying/basics/&quot; target=&quot;_blank&quot;&gt;PromQL&lt;/a&gt;&amp;nbsp;queries against the server&amp;nbsp;using its&amp;nbsp;&lt;a href=&quot;https://prometheus.io/docs/visualization/browser/&quot; target=&quot;_blank&quot;&gt;built-in expression browser&lt;/a&gt;*.&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEglGOD05dJxowpD4ZnhGa6KzOBOEgJLLN7CyU6-ediIlAJTFgWcWVvxVziD0eNA1kDq1PorccUcKyj5BBSe7xQf0YwI3Ujs1FoQnlkS4DtzkatIxiwHmyFdunupMu3XTjZY8eyl7QpAumjewykzR_qxyuQEnnLb-3bnpuVqztedSBwixkLHaA6F6v2wLA=s2221&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;901&quot; data-original-width=&quot;2221&quot; height=&quot;261&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEglGOD05dJxowpD4ZnhGa6KzOBOEgJLLN7CyU6-ediIlAJTFgWcWVvxVziD0eNA1kDq1PorccUcKyj5BBSe7xQf0YwI3Ujs1FoQnlkS4DtzkatIxiwHmyFdunupMu3XTjZY8eyl7QpAumjewykzR_qxyuQEnnLb-3bnpuVqztedSBwixkLHaA6F6v2wLA=w640-h261&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;Metrics&lt;/h2&gt;&lt;p&gt;These are the essential Kubernetes metrics to study the behavior of a container probe:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes/kubernetes/blob/42c391da29319638c3cc357cf0d0f0cc70842504/pkg/kubelet/prober/prober_manager.go#L40&quot; style=&quot;font-family: courier;&quot; target=&quot;_blank&quot;&gt;prober_probe_total&lt;/a&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;: A counter metric representing the cumulative number of a liveness, readiness, or startup probe for a container by result.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/kubernetes/kube-state-metrics/blob/master/docs/pod-metrics.md&quot; target=&quot;_blank&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;kube_pod_container_status_ready&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;:&amp;nbsp; A gauge metric describing whether the pod is ready to serve requests.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;a href=&quot;https://github.com/kubernetes/kube-state-metrics/blob/master/docs/pod-metrics.md&quot; target=&quot;_blank&quot;&gt;kube_pod_container_status_restarts_total&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;: A counter metric representing the number of container restarts per container.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/h3&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;Queries&lt;/h2&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Query #1: Table with all probe metrics:&lt;/h3&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;prober_probe_total&lt;/span&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: medium none; margin: 0px 0px 0px 40px; padding: 0px;&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span class=&quot;legend-metric-name&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px; margin-left: 1px;&quot;&gt;prober_probe_total&lt;/span&gt;&lt;span class=&quot;legend-label-brace&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;{&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;container&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;acm-agent&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;endpoint&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;https-metrics&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;instance&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;10.17....&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;job&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;kubelet&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;metrics_path&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;/metrics/probes&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;namespace&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;node&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;worker0....&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;pod&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;klusterlet-addon-workmgr-...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;pod_uid&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;5635c...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;probe_type&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;Liveness&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;result&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;failed&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;service&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;kubelet&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;legend-label-brace&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;kube_pod_container_status_ready&lt;/span&gt;&lt;/p&gt;&lt;blockquote style=&quot;border: medium none; margin: 0px 0px 0px 40px; padding: 0px;&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span class=&quot;legend-metric-name&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px; margin-left: 1px;&quot;&gt;kube_pod_container_status_ready&lt;/span&gt;&lt;span class=&quot;legend-label-brace&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;{&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;container&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;acm-agent&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;endpoint&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;https-main&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;job&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;kube-state-metrics&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;namespace&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;pod&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;klusterlet-addon-workmgr-...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;service&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;kube-state-metrics&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;legend-label-brace&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;kube_pod_container_status_restarts_total&lt;/span&gt;&lt;/p&gt;&lt;blockquote style=&quot;border: medium none; margin: 0px 0px 0px 40px; padding: 0px;&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;&lt;span class=&quot;legend-metric-name&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px; margin-left: 1px;&quot;&gt;kube_pod_container_status_restarts_total&lt;/span&gt;&lt;span class=&quot;legend-label-brace&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;{&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;container&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;acm-agent&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;endpoint&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;https-main&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;job&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;kube-state-metrics&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;namespace&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;pod&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;klusterlet-addon-workmgr-...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;,&amp;nbsp;&lt;span class=&quot;legend-label-name&quot; style=&quot;box-sizing: border-box; font-weight: 700;&quot;&gt;service&lt;/span&gt;=&lt;span class=&quot;legend-label-value&quot; style=&quot;box-sizing: border-box;&quot;&gt;&quot;kube-state-metrics&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;legend-label-brace&quot; face=&quot;-apple-system, &amp;quot;system-ui&amp;quot;, &amp;quot;Segoe UI&amp;quot;, Roboto, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Noto Sans&amp;quot;, &amp;quot;Liberation Sans&amp;quot;, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;&quot; style=&quot;background-color: rgba(0, 0, 0, 0.075); box-sizing: border-box; color: #212529; font-size: 12.8px;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;b&gt;Why&lt;/b&gt;: In general, all container metrics have the&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;namespace&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;pod&lt;/span&gt;, and&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;container&lt;/span&gt;&amp;nbsp;time series, and this is a good opportunity to see the other time series available for the metrics and plan the next queries. For instance, it is easy to see how the &lt;span style=&quot;font-family: courier;&quot;&gt;probe_type&lt;/span&gt;&amp;nbsp;and&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;result&lt;/span&gt;&amp;nbsp;time series in&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;prober_probe_total&lt;/span&gt;&amp;nbsp;are relevant for identifying probes that may be failing too often.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Query #2: All failed probes&lt;/h3&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;prober_probe_total{result=&quot;failed&quot;}&lt;/span&gt;&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; font-family: inherit; font-weight: bold; text-align: center;&quot;&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b style=&quot;text-align: left;&quot;&gt;Why&lt;/b&gt;&lt;span style=&quot;font-weight: 400; text-align: left;&quot;&gt;: Using this query in a graph helps identify containers with problems and characterizes these problems over time. Take the screenshot in Figure 1 as&amp;nbsp;an example, where each line represents a container probe (startup, readiness, or liveness.) Lines with an upward slope indicate probes that keep failing, whereas a simultaneous increase for all lines after a skipped collection cycle&amp;nbsp;likely indicates a system-wide problem.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: 400; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; font-family: inherit; font-weight: bold; text-align: center;&quot;&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv-Yb1z0fRrB-sX2Ay5pzaamaDcXsseA9geqjjfheO5_dKU-pEbj3daKlYoZjRtNlEYpewpc1QwLETo136J5IE3Z74SUSC7Rwi321N1wk1Lcue7qCdrNp9Iy0CeCTZW31EfHTI8ROsj-HO/&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Screenshot of Prometheus query evaluator&quot; data-original-height=&quot;1622&quot; data-original-width=&quot;1810&quot; height=&quot;573&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv-Yb1z0fRrB-sX2Ay5pzaamaDcXsseA9geqjjfheO5_dKU-pEbj3daKlYoZjRtNlEYpewpc1QwLETo136J5IE3Z74SUSC7Rwi321N1wk1Lcue7qCdrNp9Iy0CeCTZW31EfHTI8ROsj-HO/w640-h573/image.png&quot; title=&quot;Graph of container probes&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 1 - Prometheus query evaluator showing a graph view of failed probes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3 style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Query #3: Rate of failure for all liveness probes&lt;/span&gt;&lt;/h3&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;rate(prober_probe_total{probe_type=&quot;Liveness&quot;,result=&quot;failed&quot;}[5m])&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;b&gt;Why&lt;/b&gt;: A rate function is better at highlighting the upward slopes seen in the previous query while also &quot;smoothing&quot; out the occurrences over time ranges (5 minutes in the example.) Note how it becomes harder to pick apart individual probes but easier to see the mass spike in failures around the 12:40 mark. Also note that from the perspective of finding problems with container probes, the generalized spikes are not all that interesting since they probably indicate a problem with the cluster.&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijYS4g5aU_ZwR4lRLvoxQizvzpqRT4FC6Zljwo5Vc7JC16_WVz4PtpLm1FagwO9Smx5AKs2dOCfBqaQ4oMwhVD8HFFg83HpZ-mpBu1Meqxan3fNXvi43iSnjzKmcnJfrIZeUB6e5f0x9Qk/&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img data-original-height=&quot;1506&quot; data-original-width=&quot;1808&quot; height=&quot;547&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijYS4g5aU_ZwR4lRLvoxQizvzpqRT4FC6Zljwo5Vc7JC16_WVz4PtpLm1FagwO9Smx5AKs2dOCfBqaQ4oMwhVD8HFFg83HpZ-mpBu1Meqxan3fNXvi43iSnjzKmcnJfrIZeUB6e5f0x9Qk/w640-h547/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 2 - Graph with the rate of failures for liveness probe in the entire cluster.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;h3&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Query #4: Rate of container restarts&lt;/span&gt;&lt;/h3&gt;&lt;div&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;rate(kube_pod_container_status_restarts_total[5m])&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Why&lt;/b&gt;: Container restarts are often triggered due to successive failures of a liveness probe, but there may be other reasons, such as outright execution failures that cause the container to exit with an error code. This query offers a valuable backdrop for the next query.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;&lt;span style=&quot;text-align: left;&quot;&gt;Query #5: Rate of container restarts correlated to failures in liveness probes&lt;/span&gt;&lt;/h3&gt;&lt;div&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;rate(prober_probe_total{probe_type=&quot;Liveness&quot;,result=&quot;failed&quot;}[5m]) *&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; on(namespace,pod,container)&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;group_left&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&amp;nbsp; &amp;nbsp; rate(kube_pod_container_status_restarts_total[5m])&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Why&lt;/b&gt;: This query shows non-zero values when successive failures of a liveness probe happen within 5 minutes of a container restart. This query is handy to account for the &quot;failureThreshold&quot; setting of a liveness probe, where the container probe may fail a few times and still not trigger a container restart. As noted in the previous query, a container may restart for other reasons, which is why you want to have the results of the preceeding query on hand before drawing conclusions.&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;How&lt;/b&gt;: Unlike the previous queries, this one may be a little harder to read because it uses more advanced PromQL syntax, such as the &quot;on&quot; and &quot;&lt;a href=&quot;https://prometheus.io/docs/prometheus/latest/querying/operators/#many-to-one-and-one-to-many-vector-matches&quot; target=&quot;_blank&quot;&gt;group_left&lt;/a&gt; &quot; operators. An easier way to read the query is to start with the &quot;*&quot; operator. That operation tells Prometheus to multiply the corresponding values from the two series at each timestamp, with the &quot;on&quot; operator specifying how to match the values between the two series (by namespace, pod name, and container name, in this case.) The &quot;group_left&quot; operator specifies that the left side &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;of the multiplication&amp;nbsp;&lt;/span&gt;&lt;span&gt;(the&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;prober_probe_total&lt;/span&gt;&lt;span&gt;&amp;nbsp;metric)&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;may not have matching elements on the right side (the&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;kube_pod_container_status_restarts_total&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; metric).&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjav3P8Vn4bALV1IZk_cXnuyboC_hQr_OanekpB4Z-zhQDbE-4V-Wy0j3Uz-OdAetjhcnk1bIya-uV3EeKXxQglhLq9RiFfSK1Yys414kGOlDO-OXr8f1Ga64Dk1heHCMmLW_euUNy6e9E3/&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img data-original-height=&quot;1758&quot; data-original-width=&quot;1808&quot; height=&quot;622&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjav3P8Vn4bALV1IZk_cXnuyboC_hQr_OanekpB4Z-zhQDbE-4V-Wy0j3Uz-OdAetjhcnk1bIya-uV3EeKXxQglhLq9RiFfSK1Yys414kGOlDO-OXr8f1Ga64Dk1heHCMmLW_euUNy6e9E3/w640-h622/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 3 - Graph with container restarts correlated to failures in liveness probes&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;Query #6: Rate of container unreadiness correlated to failures in readiness probes&lt;/h3&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;rate(prober_probe_total{probe_type=&quot;Readiness&quot;,result=&quot;failed&quot;}[5m]) * on(namespace,pod,container) group_left rate(kube_pod_container_status_ready[5m])&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Why&lt;/b&gt;: This query shows non-zero values when there are successive failures of a readiness probe within 5 minutes of the kubelet presuming a container is not ready. This query is helpful to account for the &quot;failureThreshold&quot; setting of a readiness probe, where the container probe may fail a few times and still not cross the threshold.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2ixfQl9uQXraSBwvUyRDbamJiiBWaE_PJwUnYSgxu76-pCtE1T52jcB_KOLAsnymYAj93YKI_wMAgb8AzL2qcG_K_c9jyu0CieDwIjMTJo2YQHx7JZmNdIDsbnmXFNU6UWJN6RFtnEUHj/&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img data-original-height=&quot;1766&quot; data-original-width=&quot;1816&quot; height=&quot;622&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2ixfQl9uQXraSBwvUyRDbamJiiBWaE_PJwUnYSgxu76-pCtE1T52jcB_KOLAsnymYAj93YKI_wMAgb8AzL2qcG_K_c9jyu0CieDwIjMTJo2YQHx7JZmNdIDsbnmXFNU6UWJN6RFtnEUHj/w640-h622/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 4 - Graph&amp;nbsp;of container not ready correlated to failures in readiness probes&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;h3 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Query #7: Rate of liveness probe failures correlated to CPU throttling&lt;/span&gt;&lt;/h3&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;rate(prober_probe_total{probe_type=&quot;Liveness&quot;,result=&quot;failed&quot;}[5m]) * on(namespace,pod,container) group_right rate(container_cpu_cfs_throttled_periods_total[5m])&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;b&gt;Why&lt;/b&gt;: Using good practices when designing liveness&amp;nbsp;probes minimizes the chances of the probe failing prematurely, but it is still possible that applying severe CPU limits to the container may starve the probe from much-needed cycles to return prompt responses to the kubelet. A graph of this query can help you isolate liveness probe failures correlated with CPU throttling. In those cases, relaxing the probe settings or increasing the CPU allocation for the entire container may alleviate the problem.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgshAcUm6rq0dhNP7e7u4tbqotjGoaYFUd1UJ3hoMN08pAom5CIfjpU2Ql6hjJF6Rti1Yc0TYCI5DNq7XDstAABP-Qo3hh1Si9dCnT8jEG6RZsErmwCCPGiX7v-3g59-OaPPT1Fv0SQf7oq0KqnU4NTfDv4JzwVbR-jdKxW81B5XTzdquCfbTGfRAa40A=s1852&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1588&quot; data-original-width=&quot;1852&quot; height=&quot;548&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgshAcUm6rq0dhNP7e7u4tbqotjGoaYFUd1UJ3hoMN08pAom5CIfjpU2Ql6hjJF6Rti1Yc0TYCI5DNq7XDstAABP-Qo3hh1Si9dCnT8jEG6RZsErmwCCPGiX7v-3g59-OaPPT1Fv0SQf7oq0KqnU4NTfDv4JzwVbR-jdKxW81B5XTzdquCfbTGfRAa40A=w640-h548&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 5 -&amp;nbsp;Chart showing correlation of liveness probe failures with CPU throttling&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Grafana&lt;/span&gt;&lt;/h2&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;a href=&quot;https://grafana.com/&quot; target=&quot;_blank&quot;&gt;Grafana&lt;/a&gt; is a common companion to Prometheus and a good way of bringing multiple queries into a cohesive view. I spent a few minutes*&lt;/span&gt;*&lt;span style=&quot;font-family: inherit;&quot;&gt;&amp;nbsp;adding some of the queries to a dashboard&amp;nbsp;to exemplify the potential results,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;with a minor twist to the queries to make the charts look a little less cluttered.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;That twist is to only consider metrics with non-zero values by enclosing each query between parenthesis and then adding &quot;&amp;gt;0&quot; in the end, such as in this query:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote style=&quot;border: medium none; margin: 0px 0px 0px 40px; padding: 0px;&quot;&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: courier; text-align: justify;&quot;&gt;&lt;b&gt;(&amp;nbsp;&lt;/b&gt;rate(prober_probe_total{result=&quot;failed&quot;}[5m]&amp;nbsp;&lt;b&gt;)&amp;gt;0&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div style=&quot;text-align: justify;&quot;&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;The modification removes&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;from the graph&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: inherit; text-align: justify;&quot;&gt;all containers where the probes did not fail in the selected time interval.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;Figure 6 shows a snapshot of such a dashboard. You can find the&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://github.com/source-patch/blog/blob/main/k8s/probe-dashboard-grafana.json&quot; target=&quot;_blank&quot;&gt;source code&lt;/a&gt; for that dashboard in the companion GitHub repository for this blog.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: courier; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiNH5Ew_FdHcoVvgun9sVJi0xcgJv8yhQhJFrE72wqpKdngE7A-hX2s42O4vRHUnm0ZLN90pwijSuKg7boUq7BjjYn4gfXwhuUQt_4ucNbfvvLEuzKHH67ATF-4C1rDxry56_us6wizyDGaa4TRGcNI4PzClFIPpYHXPw-FGwHewWsvUHcwtmYHjH5uXQ=s2672&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;Grafana dashboard with charts for probe metrics&quot; border=&quot;0&quot; data-original-height=&quot;1640&quot; data-original-width=&quot;2672&quot; height=&quot;392&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiNH5Ew_FdHcoVvgun9sVJi0xcgJv8yhQhJFrE72wqpKdngE7A-hX2s42O4vRHUnm0ZLN90pwijSuKg7boUq7BjjYn4gfXwhuUQt_4ucNbfvvLEuzKHH67ATF-4C1rDxry56_us6wizyDGaa4TRGcNI4PzClFIPpYHXPw-FGwHewWsvUHcwtmYHjH5uXQ=w640-h392&quot; title=&quot;Grafana dashboard with charts for probe metrics&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 6 -&amp;nbsp;Grafana dashboard with charts for probe metrics&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Conclusion&lt;/span&gt;&lt;/h2&gt;&lt;div&gt;The first post in the series outlined patterns and anti-patterns&amp;nbsp;for designing effective probes for Kubernetes containers, with the second posting showing simple command-line interface invocations that quickly identify troubled containers.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In this third posting, we looked at how Kubernetes generates essential metrics about the behavior of container probes and about the general health of containers. PromQL queries combine these metrics to paint a more complete picture of how probe failures are distributed over time and their impact on container readiness and restarts.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Applying all these techniques can guide your decisions when designing container probes and help you expedite troubleshooting activities when things don&#39;t go well in operations.&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;I chose the smallest set of metrics that could illustrate these steps while still showcasing the usage of mildly complex&amp;nbsp;PromQL constructs that can become the basis for more elaborate queries. I intentionally left out the lengthier explanations for each query to keep the posting somewhat readable for broader audiences and to keep the conversation going. You can reach me&amp;nbsp;&lt;a href=&quot;https://twitter.com/dnastacio/&quot; target=&quot;_blank&quot;&gt;@dnastacio&lt;/a&gt; on Twitter.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;Happy profiling and good hunting!&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;* I used Red Hat OpenShift as the basis for this posting, in which case it is also possible to issue PromQL queries directly from the OpenShift console, via Administrator -&amp;gt; Monitoring -&amp;gt; Metrics.&lt;br /&gt;&lt;br /&gt;** Credit to&amp;nbsp;&lt;a href=&quot;https://www.linkedin.com/in/kevchu3/&quot; target=&quot;_blank&quot;&gt;Kevin Chung&lt;/a&gt;&amp;nbsp;for a precise&amp;nbsp;&lt;a href=&quot;https://www.redhat.com/en/blog/custom-grafana-dashboards-red-hat-openshift-container-platform-4&quot; target=&quot;_blank&quot;&gt;blog entry&lt;/a&gt;&amp;nbsp;on deploying Grafana to Red Hat OpenShift, the Kubernetes distribution used as the basis for all examples throughout this series.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/2554083479205097140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2022/01/kubernetes-probes-part-3-promql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2554083479205097140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2554083479205097140'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2022/01/kubernetes-probes-part-3-promql.html' title='The art and science of probing a Kubernetes container, part 3: Metrics and PromQL queries.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEglGOD05dJxowpD4ZnhGa6KzOBOEgJLLN7CyU6-ediIlAJTFgWcWVvxVziD0eNA1kDq1PorccUcKyj5BBSe7xQf0YwI3Ujs1FoQnlkS4DtzkatIxiwHmyFdunupMu3XTjZY8eyl7QpAumjewykzR_qxyuQEnnLb-3bnpuVqztedSBwixkLHaA6F6v2wLA=s72-w640-h261-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-3295909559993636243</id><published>2021-12-28T08:56:00.037-08:00</published><updated>2022-10-21T19:52:00.313-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="availability"/><category scheme="http://www.blogger.com/atom/ns#" term="container-probes"/><category scheme="http://www.blogger.com/atom/ns#" term="containers"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="modernization"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="probes"/><title type='text'>The art and science of probing a Kubernetes container, part 2: kubectl queries</title><content type='html'>&lt;p&gt;I covered design and programming tips for creating effective container probes in &lt;a href=&quot;https://sourcepatch.blogspot.com/2021/12/the-art-and-science-of-probing.html&quot; target=&quot;_blank&quot;&gt;&quot;The art and science of probing a Kubernetes container&quot;&lt;/a&gt;.&amp;nbsp;Now, it is time to look at some useful commands to inspect the behavior and effectiveness of the probes in a cluster.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;The&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/&quot; target=&quot;_blank&quot;&gt;Pod resource&lt;/a&gt;&amp;nbsp;specification combines configuration and runtime information, making the&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;kubectl&lt;/span&gt;&amp;nbsp;command-line interface a good starting point to query underperforming resources.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br class=&quot;Apple-interchange-newline&quot; /&gt;&lt;b&gt;Note:&lt;/b&gt;&amp;nbsp;All examples use the&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;-A&lt;/span&gt;&amp;nbsp;option, which means all namespaces. Replace&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;-A&lt;/span&gt;&amp;nbsp;with&amp;nbsp;&lt;span style=&quot;font-family: courier;&quot;&gt;-n $target_namespace&lt;/span&gt;&amp;nbsp;to narrow the results to a namespace.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;(Query #1) All containers that are not ready:&lt;/h2&gt;&lt;p&gt;
  
&lt;/p&gt;&lt;table style=&quot;width: 100%;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;padding: 25px;&quot;&gt;&lt;td style=&quot;background-color: #f3f3f3; width: 70%;&quot;&gt;
&lt;pre&gt;&lt;code&gt;
kubectl get pod -A -o go-template=&#39;
{{- range .items -}}{{- $pod := . -}}
  {{- range .status.containerStatuses -}}
    {{- if eq .ready false -}}
      {{- $pod.metadata.name -}}{{- &quot;,&quot; -}}
      {{- $pod.metadata.namespace -}}{{- &quot;,&quot; -}}
      {{- .name -}}{{- &quot;,&quot; -}}
      {{- .state.waiting.reason -}}{{- &quot;,&quot; -}}
      {{- .state.waiting.message -}}
      {{- &quot;\n&quot; -}}
    {{- end -}}
  {{- end -}}
{{- end -}}&#39;

&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
  &lt;td style=&quot;width: 30%;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHkyqsYD1DUuyvx0uwr2dYp1UcbnhXA1qNHgd_AWULu5KfuYHX8Mx8MX_dab2j_CSj_FITDjwJnPGhCk2P2757krPMCgZM592LArgujz3q8_mFN3ilSAF_shQEFyhGrSm_F3SG4QL1n-EY/&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;832&quot; data-original-width=&quot;950&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHkyqsYD1DUuyvx0uwr2dYp1UcbnhXA1qNHgd_AWULu5KfuYHX8Mx8MX_dab2j_CSj_FITDjwJnPGhCk2P2757krPMCgZM592LArgujz3q8_mFN3ilSAF_shQEFyhGrSm_F3SG4QL1n-EY/&quot; width=&quot;274&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;


&lt;p&gt;&lt;b&gt;Why&lt;/b&gt;: Getting a complete view of all unready containers helps identify more significant problems with the cluster, reducing the chances of misdiagnosing a system-wide problem as a problem with the tuning of probes in individual containers.&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;(Query #2) All containers that have restarted more than five times:&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;

&lt;table style=&quot;width: 100%;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;padding: 25px;&quot;&gt;&lt;td style=&quot;background-color: #f3f3f3; width: 70%;&quot;&gt;
&lt;pre&gt;&lt;code&gt;
kubectl get pod -A -o go-template=&#39;
{{- range .items -}}{{- $pod := . -}}
  {{- range .status.containerStatuses -}}
    {{- if gt .restartCount 5 -}}
      {{- $pod.metadata.name -}}{{- &quot;,&quot; -}}
      {{- $pod.metadata.namespace -}}{{- &quot;,&quot; -}}
      {{- .name -}}{{- &quot;,&quot; -}}
      {{- .restartCount -}}{{- &quot;,&quot; -}}
      {{- .lastState.terminated.reason -}}{{- &quot;,&quot; -}}
      {{- .lastState.terminated.finishedAt -}}
      {{- &quot;\n&quot; -}}
    {{- end -}}
  {{- end -}}
{{- end -}}&#39;

&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30%;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHivuxYj09EBky1LgwqKEMuwHd6qgLORQa2Anqb17ukdrX2l8n42VRLxgfM7NE5o73wPb8rhdZ_G0OI_OcUqpBQHA_D4w6Nb_9pSN__u4f-q9EgqKZkK0l6KNRVENC2EPIUDiaR-_P0p0x/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHivuxYj09EBky1LgwqKEMuwHd6qgLORQa2Anqb17ukdrX2l8n42VRLxgfM7NE5o73wPb8rhdZ_G0OI_OcUqpBQHA_D4w6Nb_9pSN__u4f-q9EgqKZkK0l6KNRVENC2EPIUDiaR-_P0p0x/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7Rpeeot6K7EqsWKYP2tZ3YgzfxNxZ3ieEf_Z3BJx_eoAB48jD-0POCtVrNb_RLvNTDLWUkat5kzDQoAihpU4CpGH8HuHfs664O4TIAPnJCdsj24qB_SWB256hYHP4BrqK5cfneUhCo0jo/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1064&quot; data-original-width=&quot;858&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7Rpeeot6K7EqsWKYP2tZ3YgzfxNxZ3ieEf_Z3BJx_eoAB48jD-0POCtVrNb_RLvNTDLWUkat5kzDQoAihpU4CpGH8HuHfs664O4TIAPnJCdsj24qB_SWB256hYHP4BrqK5cfneUhCo0jo/&quot; width=&quot;194&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
  
&lt;p&gt;&lt;b&gt;Why&lt;/b&gt;: A container terminated repeatedly is a sign of a container with fundamental problems in its processes or, more often than not, a container with a low tolerance in its liveness probe.&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;(Query #3) All containers that are not ready and have restarted more than five times:&lt;/h2&gt;

&lt;table style=&quot;width: 100%;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;background-color: #f3f3f3; padding: 25px; width: 90%;&quot;&gt;&lt;td&gt;
&lt;pre&gt;&lt;code&gt;
kubectl get pod -A -o go-template=&#39;
{{- range .items -}}{{- $pod := . -}}
  {{- range .status.containerStatuses -}}
    {{- if and (eq .ready false) (gt .restartCount 5) -}}
      {{- $pod.metadata.name -}}{{- &quot;,&quot; -}}
      {{- $pod.metadata.namespace -}}{{- &quot;,&quot; -}}
      {{- .name -}}{{- &quot;,&quot; -}}
      {{- .state.waiting.reason -}}{{- &quot;,&quot; -}}
      {{- .state.waiting.message -}}
      {{- &quot;\n&quot; -}}
    {{- end -}}
  {{- end -}}
{{- end -}}&#39;

&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;


&lt;p&gt;&lt;b&gt;Why&lt;/b&gt;: A container that keeps getting terminated and is currently unready may be a sign of fundamental stability problems in its code or, more often than not, a sign of low tolerance in its readiness and liveness probes.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;(Query #4) All containers with the same endpoint for the container liveness and readiness probes:&lt;/h2&gt;

&lt;table style=&quot;width: 100%;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;background-color: #f3f3f3; padding: 25px; width: 90%;&quot;&gt;&lt;td&gt;
&lt;pre&gt;&lt;code&gt;
kubectl get pod -A -o go-template=&#39;
{{- range .items -}}{{- $pod := . -}}
  {{- range .spec.containers -}}
    {{- if and .readinessProbe.tcpSocket.port .livenessProbe.tcpSocket.port -}}
        {{- if eq .readinessProbe.tcpSocket.port .livenessProbe.tcpSocket.port -}}
            {{- $pod.metadata.name -}}{{- &quot;,&quot; -}}
            {{- $pod.metadata.namespace -}}{{- &quot;,&quot; -}}
            {{- .name -}}{{- &quot;,&quot; -}}
            {{- .readinessProbe -}}
            {{- &quot;\n&quot; -}}
        {{- end -}}
    {{- end -}}
    {{- if and .readinessProbe.httpGet.path .livenessProbe.httpGet.path -}}
        {{- if eq .readinessProbe.httpGet.path .livenessProbe.httpGet.path -}}
        {{- if eq .readinessProbe.httpGet.port .livenessProbe.httpGet.port -}}
        {{- if eq .readinessProbe.httpGet.scheme .livenessProbe.httpGet.scheme -}}
            {{- $pod.metadata.name -}}{{- &quot;,&quot; -}}
            {{- $pod.metadata.namespace -}}{{- &quot;,&quot; -}}
            {{- .name -}}{{- &quot;,&quot; -}}
            {{- .readinessProbe -}}
            {{- &quot;\n&quot; -}}
        {{- end -}}
        {{- end -}}
        {{- end -}}
    {{- end -}}
    {{- if and .readinessProbe.exec .livenessProbe.exec -}}
        {{- if eq (print .readinessProbe.exec) (print .livenessProbe.exec) -}}
            {{- $pod.metadata.name -}}{{- &quot;,&quot; -}}
            {{- $pod.metadata.namespace -}}{{- &quot;,&quot; -}}
            {{- .name -}}{{- &quot;,&quot; -}}
            {{- .readinessProbe -}}
            {{- &quot;\n&quot; -}}
        {{- end -}}
    {{- end -}}
  {{- end -}}
{{- end -}}&#39;

&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;&lt;b&gt;Why&lt;/b&gt;: Even when the settings of a container liveness probe allow it to wait longer than the readiness probe, the primary goal of a liveness probe is to safeguard for bugs and unrecoverable errors, whereas the purpose of a readiness probe is to ensure the container can accept new requests. The checks may overlap, but the non-overlapping cases may trick the kubelet into terminating containers that are simply busy.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;(Query #5) All&amp;nbsp; containers with no startup probe and a high value for the &lt;span style=&quot;font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt;&amp;nbsp;setting&amp;nbsp;of the readiness probe:&lt;/h2&gt;

&lt;table style=&quot;width: 100%;&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;background-color: #f3f3f3; padding: 25px; width: 90%;&quot;&gt;&lt;td&gt;
&lt;pre&gt;&lt;code&gt;
kubectl get pod -A -o go-template=&#39;
{{- range .items -}}{{- $pod := . -}}
  {{- range .spec.containers -}}
    {{- if and (not .startupProbe) (.readinessProbe.initialDelaySeconds) -}}
      {{- if gt .readinessProbe.initialDelaySeconds 60 -}}
        {{- $pod.metadata.name -}}{{- &quot;,&quot; -}}
        {{- $pod.metadata.namespace -}}{{- &quot;,&quot; -}}
        {{- .name -}}{{- &quot;,&quot; -}}
        {{- &quot;readiness,&quot; -}}
        {{- .readinessProbe.initialDelaySeconds -}}
        {{- &quot;\n&quot; -}}
      {{- end -}}
    {{- end -}}
  {{- end -}}
{{- end -}}&#39;

&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;


&lt;p&gt;&lt;b&gt;Why&lt;/b&gt;: Use startup probes instead of pausing readiness probes, then break down that initial delay into multiple checks, allowing the container to become ready faster if the initialization work completes faster. For instance, use 10 checks every 6 seconds in the startup probe instead of a fixed 60-second delay in the initial delay of the readiness probe.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;(Query #6) Estimated startup duration for all containers&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;The Go templating in &lt;span style=&quot;font-family: courier;&quot;&gt;kubectl&lt;/span&gt; is powerful but has limits, so you eventually need to step up to using other tools to process the command output or write dedicated applications using the &lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/kubernetes-api/&quot; target=&quot;_blank&quot;&gt;Kubernetes API&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In a nod to the&amp;nbsp;&lt;a href=&quot;https://knowyourmeme.com/photos/572093-how-to-draw-an-owl&quot;&gt;&quot;How to draw a horse&quot;&lt;/a&gt;&amp;nbsp;meme, here is a &lt;a href=&quot;https://github.com/source-patch/blog/blob/main/k8s/probe-gist.sh&quot; target=&quot;_blank&quot;&gt;combination of &lt;span style=&quot;font-family: courier;&quot;&gt;kubectl&lt;/span&gt; and shell scripting&lt;/a&gt; I have been working on, returning all containers, probes, restart counts, and an estimation of how long each container took to become ready. You can see an output example &lt;a href=&quot;https://github.com/source-patch/blog/blob/main/k8s/output/probe-gist.csv&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh3oCNs_SSmNKpRGNyakdbuiiyEGZzg9qyz2pZS598Pw7ZJbLvfJ20jUz_eC1hu2_H8qXiJEVDpm3WQffV98MvQXSAdqfS_9jefG05TaJv5-AgewMn3PARDpp2QO62trVfer6y5R3dpjuTar7Euo5kekS7vNWfERAZSgn8dUkHIpZYhvNpt6JhMXQN64A=s2098&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;440&quot; data-original-width=&quot;2098&quot; height=&quot;134&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh3oCNs_SSmNKpRGNyakdbuiiyEGZzg9qyz2pZS598Pw7ZJbLvfJ20jUz_eC1hu2_H8qXiJEVDpm3WQffV98MvQXSAdqfS_9jefG05TaJv5-AgewMn3PARDpp2QO62trVfer6y5R3dpjuTar7Euo5kekS7vNWfERAZSgn8dUkHIpZYhvNpt6JhMXQN64A=w640-h134&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiZtM2JheYhAChjKj4-jpicp8NAKqwLrTiL6CtNF25LM9y1sU8gRmUF3DGQOfE7Gfwz5Ukvc-OVukfS-yCffPgI5eGpaN4s9e6cgn2Ytyqwal7NP0f-FskO9HKK87dnoq4uU2NwXYP4OzB_j5tdTOmLGH__bf4Cb0i5z-cQIK0kWCmAbQRc_7tVWyjGtg=s962&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;442&quot; data-original-width=&quot;962&quot; height=&quot;294&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiZtM2JheYhAChjKj4-jpicp8NAKqwLrTiL6CtNF25LM9y1sU8gRmUF3DGQOfE7Gfwz5Ukvc-OVukfS-yCffPgI5eGpaN4s9e6cgn2Ytyqwal7NP0f-FskO9HKK87dnoq4uU2NwXYP4OzB_j5tdTOmLGH__bf4Cb0i5z-cQIK0kWCmAbQRc_7tVWyjGtg=w640-h294&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I must emphasize that the startup duration (measured in seconds) in the above example is only a rough estimate because the pod specification does not break down all the timestamps for the container lifecycle. &lt;br /&gt;&lt;br /&gt;&lt;div&gt;Also note that if a container is terminated and then restarted within the pod, there are situations where the last termination timestamp is not recorded, making it impossible to determine the duration of the last startup.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;References&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;a href=&quot;https://cloud.redhat.com/blog/customizing-oc-output-with-go-templates&quot; target=&quot;_blank&quot;&gt;&quot;Customizing OC Output With Go Templates&quot;&lt;/a&gt;, though you need to remember to replace &quot;&lt;span style=&quot;font-family: courier;&quot;&gt;oc&lt;/span&gt;&quot; with &quot;&lt;span style=&quot;font-family: courier;&quot;&gt;kubectl&lt;/span&gt;&quot; in the examples if you are not using a &lt;a href=&quot;https://www.redhat.com/en/technologies/cloud-computing/openshift&quot; target=&quot;_blank&quot;&gt;Red Hat OpenShift cluster&lt;/a&gt; (&quot;&lt;span style=&quot;font-family: courier;&quot;&gt;oc&lt;/span&gt;&quot; is OpenShift&#39;s enhanced, yet compatible, version of &quot;&lt;span style=&quot;font-family: courier;&quot;&gt;kubectl&lt;/span&gt;&quot;).&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://pkg.go.dev/text/template#pkg-functions&quot; target=&quot;_blank&quot;&gt;Go-template functions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://kubernetes.io/docs/reference/kubectl/cheatsheet&quot; target=&quot;_blank&quot;&gt;kubectl cheat sheet&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/3295909559993636243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2021/12/6-kubectl-queries-for-validating.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/3295909559993636243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/3295909559993636243'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2021/12/6-kubectl-queries-for-validating.html' title='The art and science of probing a Kubernetes container, part 2: kubectl queries'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHkyqsYD1DUuyvx0uwr2dYp1UcbnhXA1qNHgd_AWULu5KfuYHX8Mx8MX_dab2j_CSj_FITDjwJnPGhCk2P2757krPMCgZM592LArgujz3q8_mFN3ilSAF_shQEFyhGrSm_F3SG4QL1n-EY/s72-c" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-5391957188388444918</id><published>2021-12-17T15:32:00.032-08:00</published><updated>2023-04-10T09:53:21.723-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="availability"/><category scheme="http://www.blogger.com/atom/ns#" term="container-probes"/><category scheme="http://www.blogger.com/atom/ns#" term="containers"/><category scheme="http://www.blogger.com/atom/ns#" term="kubernetes"/><category scheme="http://www.blogger.com/atom/ns#" term="modernization"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="probes"/><title type='text'>The Art and Science of Probing a Kubernetes Container</title><content type='html'>&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Keeping containers alive in a Kubernetes cluster can feel more like art than science.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In this article, I dive into the sea of madness awaiting those responsible for authoring &lt;a href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe&quot; target=&quot;_blank&quot;&gt;container probes&lt;/a&gt;, with particular attention to the relatively new addition of startup probes to the mix. Along the way, I leave a breadcrumb trail of curated links you can use to take the next step in implementing the various suggestions in the article.&lt;/span&gt;&lt;/p&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: right;&quot;&gt;&lt;br /&gt;&lt;/div&gt;Starting, nay, requesting the start of a new container in a Kubernetes cluster is relatively simple: provide a &lt;a href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/&quot; target=&quot;_blank&quot;&gt;PodSpec&lt;/a&gt; to the cluster, possibly as a &lt;a href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-template-v1/#PodTemplateSpec&quot; target=&quot;_blank&quot;&gt;PodTemplateSpec&lt;/a&gt; wrapped inside one of the various flavors of &lt;a href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/&quot; target=&quot;_blank&quot;&gt;workload resources&lt;/a&gt;. After receiving the PodSpec, the &lt;a href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/&quot; target=&quot;_blank&quot;&gt;kube-scheduler&lt;/a&gt; assigns the pod to a node, then the &lt;a href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;kubelet&lt;/b&gt;&lt;/a&gt; in that node starts the containers in the pod.&lt;/span&gt;&lt;div&gt;&lt;span style=&quot;color: #0e101a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Pods follow a clear &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle&quot; target=&quot;_blank&quot;&gt;lifecycle&lt;/a&gt;, and part of that lifecycle requires the kubelet to keep tabs on the containers in the pod, to ensure they are responsive throughout their existence, with remedial actions ranging from suspending traffic to the pod to terminating the pod.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;As background, there are &lt;a href=&quot;https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/&quot; target=&quot;_blank&quot;&gt;three types of probes&lt;/a&gt; a developer can include in a container specification:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Readiness probes&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;: This probe tells the kubelet when the container is ready to process requests. It is the most prevalent of container probes.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Liveness probes&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;: This is the &quot;break in case of emergency&quot; probe. Ideally, containers should exit after realizing they can no longer do their job, but bugs are rarely graceful in their symptoms. A kubelet terminates containers that do not respond successfully in a specified interval.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Startup probes:&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;We could also call them the &quot;I just got here, leave me alone&quot; probes. It tells the kubelet when to start evaluating readiness and liveness probes.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgd_cWosj7jv23CJ35rhD0qfXXJb8ctjJSND9GMDM3jneJTYRpOIV7ms0RPXvuF9h5kc0cI5CrYBkowN2M5b-yxyDud0Q0DdLSEZ5zPijlkIByBYoJetthWeQUHm_fUFeiPFUJr3dWMzD-D5HzSOWoderHkggpd9xj_QmYGpxIP5sgIRz8VzgaVv1wrXQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img data-original-height=&quot;268&quot; data-original-width=&quot;640&quot; height=&quot;268&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgd_cWosj7jv23CJ35rhD0qfXXJb8ctjJSND9GMDM3jneJTYRpOIV7ms0RPXvuF9h5kc0cI5CrYBkowN2M5b-yxyDud0Q0DdLSEZ5zPijlkIByBYoJetthWeQUHm_fUFeiPFUJr3dWMzD-D5HzSOWoderHkggpd9xj_QmYGpxIP5sgIRz8VzgaVv1wrXQ=w640-h268&quot; title=&quot;Figure 1 - Relationship between container probes and a pod lifecycle&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;Figure 1 - Relationship between container probes and a pod lifecycle&lt;/div&gt;&lt;h2 style=&quot;background: none 0% 0% repeat scroll transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;h2 style=&quot;background: none 0% 0% repeat scroll transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;Readiness probes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;If a container fails to respond to its readiness probe, the kubelet removes the container from the service load balancer, effectively diverting traffic away from the container. Here, the developer hopes that a replica elsewhere can handle that traffic.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0e101a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The design of a readiness probe is somewhat straightforward. You want to take into account the state of dependencies and the resource usage in the container:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Dependencies&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. If your container depends on something like a  database server or another remote server, those types of dependencies tend to offer an endpoint or command-line interface to assess their readiness. If the dependencies are in the critical path of serving requests to clients, then factor in the dependency status in the calculation of the readiness status of the probe.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Maximum allowed connections&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Many frameworks have a maximum configured limit for accepting new connections, so factor that in as well.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;System resources&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. This one is not as obvious, but running close to memory ceilings and running out of space in a filesystem are known for destabilizing processes. You want the cluster to stop sending traffic to the pod before running out of system resources, so consider failing probe calls when these limits reach a certain threshold of the maximum. One of my least favorite forms of resource exhaustion is running out of file handles, which is harder to detect than a simple lack of disk space and can block even the most basic troubleshooting tasks.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Do&#39;s:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Have a probe&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Always define a readiness probe for your runtime containers. You may feel like your container clients can deal with the container becoming unresponsive. Still, there is never a good reason to let the cluster route requests to a container that may not be ready to handle the requests.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Have the status ready&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Consider assessing the status of remote dependencies and resource utilization outside the thread servicing the readiness probe. Readiness probes have a timeout value, and it is best to return a clear failure code immediately than risk timing out a response while gathering input from all dependencies.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Don&#39;ts:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Do not exceed the limits of the liveness probe&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. If the container also has a liveness probe, do not make the maximum time tolerance (&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt; * &lt;span style=&quot;background-color: #f3f3f3;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;&lt;/span&gt;) longer than the maximum tolerance for the liveness probe. That is a recipe for letting the cluster route requests to a potentially hopeless container about to crash.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Do not mix slowness with readiness.&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;A slow response is still a response. You may feel like your container must let callers know that it is not ready because a dependency is taking much longer than usual to process requests, but that is a concern best left for the observability discipline.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;background: none 0% 0% repeat scroll transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Liveness probes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;If a container fails to respond to this probe consecutively, the kubelet will terminate the container. Emphasis on &quot;terminate&quot; versus &quot;restart,&quot; which depends on the &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy&quot; target=&quot;_blank&quot;&gt;restart policy&lt;/a&gt; of the pod.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0e101a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;These probes are notoriously difficult to code correctly because the goal of the probe&#39;s developer is to anticipate the unexpected, such as a bug in a process that could put the whole container in an unrecoverable state.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;If the probe is too lenient, the container may become unresponsive without being terminated, effectively reducing the number of replicas of that pod with a chance of serving traffic.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;If the probe is too strict, the container may keep getting terminated unnecessarily, a condition that is insidiously hard to detect when happening intermittently, risking the pod looking healthy right when you are looking for problems.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Do&#39;s:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Define a liveness probe&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Not having a liveness probe means leaving your container exposed to becoming permanently unresponsive due to a bug, so always give it a try.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Monitor resources&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Cover resources like filesystem space, file handles, and memory. These resources are notorious for locking up containers when exhausted. It is wiser to return a failure when memory utilization passes the 90% mark than risking becoming completely unresponsive after hitting 100%. The probe has timeout values, but it is always best to return a clear failure code than let the kubelet infer a crash from a timeout.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Use commands&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Favor invoking commands instead of tcp or http requests. This advice may be controversial, but invoking a shell command uses a lower-level interface, which in turn has a higher chance of allowing your code to assess the internal state of the container. I have met my share of web servers that are happy to respond to simple ping requests even while half-crashed due to lack of memory.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Micro control-planes&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. If possible, use a different connection pool than the one used to serve customer traffic, or set a connection aside specifically for the probes. Think of the distinction between control planes and &lt;a href=&quot;https://kubernetes.io/docs/concepts/overview/components/&quot; target=&quot;_blank&quot;&gt;regular workloads&lt;/a&gt; in the cluster but on a much smaller scale. Unless your liveness probe has a dedicated connection for answering the liveness probe, there is a chance that the container is busily servicing customer traffic (and appropriately reporting not being ready through its readiness probe.) Terminating the container under those conditions is harmful since the cluster ends up (temporarily) having even fewer containers to service actual requests.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Have the status ready&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Similar to the suggestion in the section about liveness probes, consider assessing the liveness of the container outside the thread servicing the liveness probe. Liveness probes have a timeout value, and it is best to return a clear failure code immediately than risk timing out a response while gathering input from all dependencies.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;/div&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Don&#39;ts:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Readiness is not liveness:&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;Do not check for the availability of dependencies. If they are failing, it is the responsibility of the readiness probe, and terminating the pod is very unlikely to help matters.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Do not reuse the readiness criteria:&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;I often see container probes hitting the same container endpoint but using different thresholds in &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;&amp;nbsp;and &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;. The concerns of a liveness probe are distinct from those of a readiness probe. A container may be unable to handle traffic due to external factors, and a liveness probe using the same endpoint as a readiness probe risks compounding the problem by telling the kubelet to terminate the container.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Tolerate more than readiness probe&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;: Whether you are looking at the &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;,&amp;nbsp;&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;, or considering the availability of system resources in the container, make sure that the tolerances of the liveness probe exceed the patience of the readiness probe. For instance, making the maximum time tolerance (&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt; + &lt;span style=&quot;background-color: #f3f3f3;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;&lt;/span&gt;&amp;nbsp;* &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;) shorter than the maximum tolerance for the readiness probe is a recipe for terminating the container prematurely while still servicing remote requests.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Do not try to be conservative&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;: In doubt, err on the side of leniency, and set higher values for &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;, &lt;span style=&quot;background-color: #f3f3f3;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;&lt;/span&gt;, and &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt;, giving your container plenty of latitude to report being alive. Unexpected hung processes are an edge case and far more rare than slow responding processes, and a liveness probe should favor the most common causes. A good rule of thumb is using a total tolerance that is twice as long or longer than the tolerance of a readiness probe.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjJP3l9Y-NWcqSaDfeXgTAYrmaPEhLo_5wf-DfyoMlgGR8xV6Z0gzZywuSUXExN1n-c2jsD7hQwh8BZ9uBU3F4ADF6mV4iNdxz2Sr45UAo87LIXCJX6DFyovrAqZClGLArigf8lDECjnW2ZfvKit87ZuSLPlPkqPdi9_IvVjSVomRWXh4o3Q4AGRgKc3w&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img data-original-height=&quot;264&quot; data-original-width=&quot;640&quot; height=&quot;264&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjJP3l9Y-NWcqSaDfeXgTAYrmaPEhLo_5wf-DfyoMlgGR8xV6Z0gzZywuSUXExN1n-c2jsD7hQwh8BZ9uBU3F4ADF6mV4iNdxz2Sr45UAo87LIXCJX6DFyovrAqZClGLArigf8lDECjnW2ZfvKit87ZuSLPlPkqPdi9_IvVjSVomRWXh4o3Q4AGRgKc3w=w640-h264&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 2 - A liveness probe should allow more time to completely fail than the readiness probe&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span style=&quot;background: transparent; color: #0e101a; font-weight: normal; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Startup probes&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Startup probes are a relatively new addition to the stable of container probes, achieving GA status in late 2020, in &lt;a href=&quot;https://kubernetes.io/blog/2020/12/08/kubernetes-1-20-release-announcement/&quot; target=&quot;_blank&quot;&gt;Kubernetes 1.20&lt;/a&gt;. Note: Credit to my colleague, the ever knowledgeable Nathan Brophy, for pointing out the feature was &lt;a href=&quot;https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/&quot; target=&quot;_blank&quot;&gt;already available by default&lt;/a&gt;, albeit in beta stage, as early as of Kubernetes 1.18.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: right;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;A startup probe creates a &quot;buffer&quot; in the lifecycle of containers that need an inordinate amount of time to become ready.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;color: #0e101a;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In the past, in the absence of startup probes, developers resorted to a mix of using &lt;a href=&quot;https://kubernetes.io/docs/concepts/workloads/pods/init-containers/&quot; style=&quot;background-color: transparent;&quot; target=&quot;_blank&quot;&gt;initialization containers&lt;/a&gt; and setting long &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt;&amp;nbsp;&lt;a href=&quot;https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#probe-v1-core&quot; style=&quot;background-color: transparent;&quot; target=&quot;_blank&quot;&gt;values for readiness and liveness probes&lt;/a&gt;, each with its own set of compromises:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background: transparent; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;It can wait but shouldn&#39;t.&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;Initialization containers free up developers to isolate specific tools and security privileges from the runtime container, but are a heavy-handed way of waiting for external conditions. They run serially until completion, and because they are separate containers, it may be cumbersome to transfer the result of their work to other containers in the pod.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Slow starts.&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;Long pauses set via the &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt; field on a readiness probe can waste time during a container&#39;s startup because the kubelet always waits that much time before considering sending traffic to the pod.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Consider whether your existing liveness and readiness probes take relatively long to start and replace high values of &lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-color: #f3f3f3; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(243, 243, 243); color: #0e101a; font-family: courier; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;initialDelaySeconds&lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt; with an equivalent startup probe.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;For instance, this container spec below:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;spec:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp;containers:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp;- name: myslowstarter&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;image: ...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;readinessProbe:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tcpSocket:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;port: 8080&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;initialDelaySeconds: 600&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;periodSeconds: 10&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;livenessProbe:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tcpSocket:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;port: 8080&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;initialDelaySeconds: 600&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;periodSeconds: 20&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;can be significantly improved by moving that delay to be observed in a startup probe, like this:&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;spec:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp;containers:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp;- name: myslowstarter&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;image: ...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;readinessProbe:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tcpSocket:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;port: 8080&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;periodSeconds: 10&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;s style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;initialDelaySeconds: 600&lt;br /&gt; &lt;/span&gt;&lt;/s&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; livenessProbe:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tcpSocket:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;port: 8080&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;periodSeconds: 20&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;s style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;initialDelaySeconds: 600&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;s style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; startupProbe:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;tcpSocket:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;port: 8080&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;failureThreshold: 60&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;&lt;strong style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;periodSeconds: 10&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In the first example, the kubelet always waits 600 seconds before evaluating the readiness and liveness probes. In contrast, in the second example, the kubelet checks&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;up to&lt;/span&gt;&lt;/em&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;60 times in 10-second intervals, thus enabling the container to start as soon as it meets its startup conditions.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;A hidden benefit of the frequent checks in a startup probe is that it enables a developer to set a high value of &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;&amp;nbsp;and &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;&amp;nbsp;without worrying about slowing down the container startup. In contrast, the unwieldy observance of &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt;&amp;nbsp;puts pressure on developers to ignore edge cases and set lower values that allow the entire application to start faster. In my experience, &quot;edge cases&quot; are synonymous with&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;things we have not seen during development,&quot;&lt;/span&gt;&lt;/em&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;which translates to unstable containers in some production environments.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;As a rule of thumb, use startup probes if the&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt;&amp;nbsp;field in your readiness and liveness probes exceeds the total time specified through&amp;nbsp;&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;&amp;nbsp;*&amp;nbsp;&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;&amp;nbsp;fields. As a companion rule of thumb, anything over 60 seconds for&amp;nbsp;&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;initialDelaySeconds&lt;/span&gt;&amp;nbsp;in a readiness or liveness probe is a good sign that your application would benefit from using a startup probe instead.&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;background: transparent; color: #0e101a; font-weight: normal; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/h2&gt;&lt;h2 style=&quot;background: transparent; color: #0e101a; font-weight: normal; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Timing is everything&lt;/span&gt;&lt;/h2&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;After observing the suggestions in this article, you are ready to ask the inevitable question:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;So, what should I use for the &lt;a href=&quot;https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe&quot; target=&quot;_blank&quot;&gt;probe settings&lt;/a&gt;?&quot;&lt;/span&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;For &lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-color: #f3f3f3; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; background: rgb(243, 243, 243); color: #0e101a; font-family: courier; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;timeoutSeconds&lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;, I would recommend keeping the value at its default (one second.) This suggestion builds atop my other advice for assessing the responses of a probe outside the thread answering the kubelet request. A quick answer about a problem is always better than letting the kubelet infer the result from a timeout.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;For the combination of&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;&amp;nbsp;and&amp;nbsp;&lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;, more checks in the same interval tend to be more accurate than fewer checks. Assuming you followed the suggestion of assessing the container status separately from the thread responding to the request, more frequent checks will not add significant overhead to the container.&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2 style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Mind your CPU limits&lt;/span&gt;&lt;/h2&gt;&lt;div&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Different clusters, different speeds.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;A common problem with probes, specially liveness probes, is to assume a cluster will always give your container as much CPU as you request. The other common mistake is to assume that clusters will always observe fractional requests with surgical precision.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Starting with the hypervisor and the VMs hosting worker nodes, all the way to the &lt;a href=&quot;https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/&quot; target=&quot;_blank&quot;&gt;CPU limits in a pod specification&lt;/a&gt;, there are myriad reasons why a container can run the same stretch of code at different speeds.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here are the top factors that can blind-side a developer:&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;b&gt;Overcommitted CPUs in the hypervisor&lt;/b&gt;: Shared VMs in the IaaS provider. Even identical hardware and networking speeds can be affected by the occasional &quot;noisy neighbor&quot; hitting a burst of CPU usage. Modern hypervisors are pretty good at compensating for such bursts and even throttling processes, but an IaaS may overcommit CPUs under the assumption processes will not all burst at the same time.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Infinitesimal CPU requests&lt;/b&gt;:&amp;nbsp;Setting a CPU limit of 20ms for CPU allocation to a container may seem like a responsible, conscious decision for a container that rarely does any processing. However, in the real world, a worker node does not have a tiny vCPU 2% the size of a full vCPU. The worker node attempts to simulate that tiny vCPU by giving your container an entire vCPU during a small slice of time, resulting in a &quot;lumpy&quot; allocation of CPU to the container. As a result, the container may find itself receiving a lot more CPU than requested for a brief interval and then entirely paused for longer than expected.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Keep those two factors in mind when setting the values for probes, especially liveness probes. Learning a bit about the hardware characteristics and overcommitment settings of your IaaS provider can go a long way in deciding the safety multipliers to add to settings like&amp;nbsp;&lt;span style=&quot;background-color: #f3f3f3; color: #0e101a; font-family: courier;&quot;&gt;timeoutSeconds&lt;/span&gt;, &lt;span style=&quot;background-color: #f3f3f3; color: #0e101a; font-family: courier;&quot;&gt;failureThreshold&lt;/span&gt;, and&amp;nbsp;&lt;span style=&quot;background-color: #f3f3f3; color: #0e101a; font-family: courier;&quot;&gt;periodSeconds&lt;/span&gt;. Depending on what you learn, you may also reconsider the settings for CPU requests and limits so that your probes have enough processing capacity to respond to requests promptly.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh9IviqNgaL-7z-QfDwbYZ1Bh3CR74HZKY31Ituq72_GYERXLE7KpXSOtEw4u0TA3GznKJAd1quMktN74GDGRV5NeJ0mkus56WcRIQYpGlWa5VSAfjTnlVYinHzA-ueLrekTsII07kZJ5gVVYK_p7bwJPsG7oL6wSyetQ6kH1XdG2dP6jBllWjkdapYbw&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img data-original-height=&quot;386&quot; data-original-width=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEh9IviqNgaL-7z-QfDwbYZ1Bh3CR74HZKY31Ituq72_GYERXLE7KpXSOtEw4u0TA3GznKJAd1quMktN74GDGRV5NeJ0mkus56WcRIQYpGlWa5VSAfjTnlVYinHzA-ueLrekTsII07kZJ5gVVYK_p7bwJPsG7oL6wSyetQ6kH1XdG2dP6jBllWjkdapYbw=s16000&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 3 -&amp;nbsp;Healthy container getting terminated due to a restrictive CPU limit&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Conclusion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;This article offers a range of suggestions to improve the precision and performance of container probes, allowing containers to start faster and stay running longer.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The next step comes from careful analysis of what runs inside the containers and studying their behavior in actual runtime across a diverse set of clusters and conditions, going as far as simulating failures of dependencies and reduced availability of system resources. Using the &lt;span style=&quot;background-color: #f3f3f3; font-family: courier;&quot;&gt;kubectl&lt;/span&gt; utility and its ability to format and filter contents is a great way to find containers with a high number of restarts and inadequate probe limits, which is a more technical subject covered &lt;a href=&quot;https://sourcepatch.blogspot.com/2021/12/6-kubectl-queries-for-validating.html&quot; style=&quot;background-color: transparent;&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;. Using PromQL with Kubernetes metrics can further expand that technique with charts for various time series, a topic covered in this other &lt;a href=&quot;https://sourcepatch.blogspot.com/2022/01/kubernetes-probes-part-3-promql.html&quot; style=&quot;background-color: transparent;&quot; target=&quot;_blank&quot;&gt;posting&lt;/a&gt;.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In summary, keep the goal of the probes in mind when writing them, ensure they run quickly and assuredly, providing clear information with minimal (if any) false positives in their response to the kubelet. Then trust the cluster to do what it does best with the data, ensuring maximum availability of your containers to their clients.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background: transparent; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/5391957188388444918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2021/12/the-art-and-science-of-probing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5391957188388444918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5391957188388444918'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2021/12/the-art-and-science-of-probing.html' title='The Art and Science of Probing a Kubernetes Container'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgd_cWosj7jv23CJ35rhD0qfXXJb8ctjJSND9GMDM3jneJTYRpOIV7ms0RPXvuF9h5kc0cI5CrYBkowN2M5b-yxyDud0Q0DdLSEZ5zPijlkIByBYoJetthWeQUHm_fUFeiPFUJr3dWMzD-D5HzSOWoderHkggpd9xj_QmYGpxIP5sgIRz8VzgaVv1wrXQ=s72-w640-h268-c" height="72" width="72"/><thr:total>2</thr:total><georss:featurename>Raleigh, NC, USA</georss:featurename><georss:point>35.7795897 -78.6381787</georss:point><georss:box>7.469355863821157 -113.7944287 64.089823536178841 -43.4819287</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-3785323428538881341</id><published>2021-09-06T12:32:00.014-07:00</published><updated>2022-08-19T12:35:12.285-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="agile"/><category scheme="http://www.blogger.com/atom/ns#" term="devops"/><category scheme="http://www.blogger.com/atom/ns#" term="on-call"/><title type='text'>Should (only) developers be on-call?</title><content type='html'>&lt;section class=&quot;section section--body&quot; name=&quot;1102&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;1937&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;section class=&quot;section section--body&quot; name=&quot;1102&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p style=&quot;text-align: left;&quot;&gt;The question “should developers be in the on-call rotation?” is a frequent debate in technical forums, with the narrow nature of the question demanding polarization of the community around the answer.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;42d5&quot;&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b333&quot;&gt;I don’t like that question as a starting point because it preempts all other discussions on how to make (or keep) the system manageable without requiring operators with intimate knowledge of the source code.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2dd2&quot;&gt;This story examines the negative effects of on-call rotation on people and how addressing their causes also results in systems where non-developers can join the on-call rotation in a healthy and effective manner.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;18a2&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;492f&quot;&gt;Why do I even need an on-call rotation?&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;365d&quot;&gt;The order of the discussion goes:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;bedc&quot;&gt;Anything done on a sustained basis needs a system.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;38df&quot;&gt;Even in a well-designed system, things don’t always go according to plan.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;bfef&quot;&gt;That gap in the plan may happen at any time because online systems never stop.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;5cb0&quot;&gt;Without a scripted procedure, the best chance of resolution lies with brains wired by millennia of adaptations to life-and-death circumstances.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;ae3a&quot;&gt;The unpredictability of that exceptional event requires an on-call schedule.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;0416&quot;&gt;Should a developer be the person answering that pager? And to go further, should developers be the first people answering that pager?&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;0f9b&quot;&gt;If not, then who?&lt;/li&gt;&lt;/ol&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f3d4&quot;&gt;Ah, clarity! Or at least more of it.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a30f&quot;&gt;Before diving into answers, we must understand that people are more than actors in the system: they are also a part of it. This shift in perspective augments the scope of sustainable delivery, especially when we look at the science behind the psychological effects on people.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;c8e0&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;b51e&quot;&gt;Psychology of&amp;nbsp;on-call&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;82ff&quot;&gt;Without getting too deep into the excellent resources listed at the end of this posting, there is a scientific basis demonstrating how on-call shifts increase anxiety and stress on people supporting the system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2554&quot;&gt;Lack of control is at the core of the findings:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;29b0&quot;&gt;The inherent lack of control in being called out of regular business hours.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;8a36&quot;&gt;Lack of control over the causes of the problem.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;3b01&quot;&gt;Uncertainty about having the skills, tools, and support to handle the situation.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;62e1&quot;&gt;The studies show that the mere expectation of being paged produces similar anxiety and stress levels to being paged. The fear of missing an alert while on-call further magnifies the degradation of people’s sleep patterns.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5442&quot;&gt;Taken to extremes, where the system routinely wakes people in the middle of the night, an on-call schedule &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://time.com/3657434/night-work-early-death/&quot; href=&quot;https://time.com/3657434/night-work-early-death/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;may even reduce life expectancy for responders&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d567&quot;&gt;Without going further into this rabbit hole of doom, it is clear that any sustainable system must consider its contributors from the onset. The design must include clear service level objectives for calling out people, systematic training on troubleshooting techniques, and a robust support system for people once they start handling the incident.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;95ad&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;9329&quot;&gt;Predictability as the basis of&amp;nbsp;sanity&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;da54&quot;&gt;Based on the science of psychological effects on responders, it is evident that we need to pay close attention to the frequency and intensity of on-call shifts.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7688&quot;&gt;Addressing the frequency portion requires a continuum of approaches, ranging from preemptive to adaptive.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1780&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://en.wikipedia.org/wiki/Shift-left_testing&quot; href=&quot;https://en.wikipedia.org/wiki/Shift-left_testing&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Shift-left testing&lt;/a&gt; is an excellent example of a preemptive approach focused on earlier system validation across design, development, and testing.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;246b&quot;&gt;&lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.cloudbees.com/blog/why-and-how-testing-in-production&quot; href=&quot;https://www.cloudbees.com/blog/why-and-how-testing-in-production&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Testing in production&lt;/a&gt; is the most comprehensive example of an adaptive approach, aiming at rollouts gradually gated and validated by actual runtime results.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;664b&quot;&gt;Addressing the intensity portion comes later, in section “Asking permission, not forgiveness.”&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;d903&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;d0bd&quot;&gt;Limits. We all have&amp;nbsp;them.&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9b43&quot;&gt;Every system looks much better when unconstrained by limits, but the average system always has limits.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d8e8&quot;&gt;The above-average system has documented limits. A great one has written procedures for dealing with each exceeded limit.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a34b&quot;&gt;A superb system has people continuously working towards removing the limits or automating the handling of blown ceilings.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;50f7&quot;&gt;We are at the point where you remember I wrote that people are part of the system. People also have limits. The limits may vary with personal circumstances and skills, but they exist, and, unlike machine limits, they cannot be quickly removed or automated.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a98a&quot;&gt;As an operations manager will tell you, dealing with systems at the limit is a volatile business. When it comes to employees experiencing their limits, it can be borderline dangerous to colleagues and, ultimately, the company.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b33b&quot;&gt;An operations manager has a direct vantage point into non-human limits and the mechanisms to address those failures by adding more capacity and coordinating the deployment of software fixes. On the other hand, a people manager may have an obstructed view of the state of personal stress in his team and how people cope with the stress of being part of the larger system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7782&quot;&gt;For a people manager, the solution to an unclear picture of employees’ stress and anxiety passes through the same gates as the overall system: preempt and adapt.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1187&quot;&gt;Preempting anxiety and stress means ensuring the people on-call have an outsized voice in the system’s architecture, design, and rollout.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;8836&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;31ed&quot;&gt;Asking permission, not forgiveness&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;fb58&quot;&gt;If someone is on the hook to handle a system outage off-hours, that person must have a voice in what will be in that system then. Without a voice, that person may not know what they are dealing with while interacting with the system.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b393&quot;&gt;The best form of participation happens early in the cycle, starting with architectural reviews. A documented system architecture is the only way to involve the operations people in that process. I think we all heard our share of “the system is the code” statements, but strings of code are rarely an efficient way of conveying abstractions. The thinking is also downright unhelpful during an outage of a system with hundreds of thousands of lines of code written in 5 different programming languages (“what, your ops people don’t know Ruby, Go, Java and Node? Sheesh!”)&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b8ba&quot;&gt;An architectural review is a time for on-call people to probe every arrow of the system diagram for limits and error conditions.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5bc4&quot;&gt;You want to ask:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;d5db&quot;&gt;What are the system limits? Probe for network bandwidth usage, system resource consumption, and maximum horizontal and vertical scales.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;b26c&quot;&gt;What are the error conditions? Probe for the possibility of network outages and individual component failures in the system diagram.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;be21&quot;&gt;How are limits and errors perceived? Will the system administrators notice rejected requests, slow responses, reroutes to static CDN, etc.?&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f799&quot;&gt;Can error conditions cause the system to exceed limits more quickly?&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;f51f&quot;&gt;Will these exceeded limits cause system errors?&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;d620&quot;&gt;How should one handle exceeded limits? &lt;a class=&quot;markup--anchor markup--li-anchor&quot; data-href=&quot;https://www.section.io/blog/scaling-horizontally-vs-vertically/&quot; href=&quot;https://www.section.io/blog/scaling-horizontally-vs-vertically/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Scale out horizontally, scale out vertically, or both&lt;/a&gt;? This question is also an opportunity to ask about components that do not tolerate horizontal or vertical scaling.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;8ffa&quot;&gt;And ultimately, for one of the most crucial questions: Which parts of the system automatically handle these conditions and which ones require human judgment and subsequent manual intervention?&lt;/li&gt;&lt;/ol&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0c47&quot;&gt;Under no circumstance should a system leave the architecture stage without an answer or scheduled follow-ups to each of these questions. And if the answer to the last question leans too much towards “people,” you have my permission to quote &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.youtube.com/watch?v=b2aH9tu4s30&quot; href=&quot;https://www.youtube.com/watch?v=b2aH9tu4s30&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;this scene from the movie Soylent Green&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;acf7&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;efe1&quot;&gt;Beyond design: total cost of ownership&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c2a4&quot;&gt;TCO, or total cost of ownership, is the most under-appreciated factor in maintaining a system and one of the most glaring blind spots for system architects, designers, and developers.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;edf4&quot;&gt;As a general rule, people without experience in operations engineering will overestimate the capacity of operations teams and underestimate the financial costs of keeping the system running. Everything, in systems or life, has a cost, whether it is a direct economic cost of paying for goods or services or the indirect lost-opportunity cost of investing time in an activity.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9501&quot;&gt;I once worked in an organization where development and operations reported into different silos with separate budgets (you can see where this is going.) This organization and the product no longer exist, so I can share a more relatable example of how a lack of TCO awareness caused severe and long-lasting damage.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;453d&quot;&gt;In a 6-month interval, the development team introduced two new types of backend servers into a SaaS offering without consulting with the operations team other than informing them of the date they should deploy the new servers. The operations manager accepted the imposition under the condition that the development team was available to support the new servers&lt;em class=&quot;markup--em markup--p-em&quot;&gt; “until the operations team acquired the skills required to maintain them,”&lt;/em&gt; without committing to specific transition dates.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;9adc&quot;&gt;Without a plan or cost controls, the operations team took an entire year to find enough training budget to close the skill gap, let alone code the monitoring bridges from the monitoring platform to the new systems. In the meantime, the development team started spending most of its time on routine system upgrades, coding those bridges from the monitoring systems, and assisting in troubleshooting system outages. To make matters worse, some of the outages did not trace back to the new backend systems but required paging developers to rule out the new backend servers as the cause of the incident.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;34cb&quot;&gt;Suddenly, the product manager started to receive pushback from a hamstrung development team, affecting committed features and prompting customers to wait before signing new contracts until the committed features were available.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b05a&quot;&gt;The most insidious aspect of authorizing a deployment without knowing its total cost of ownership is that the organization is effectively signing a blank check against its operations and development budgets, and blank checks are not recipes for sustainable businesses.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;7fad&quot;&gt;Also, beware of the “feature I wrote on the weekend” since a prototype will typically cost 30–50 times more to become a stable, managed feature in production, whether or not the development organization is mature enough to estimate the actual TCO of the feature.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;aabc&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;0a66&quot;&gt;Why developers, though?&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;73c0&quot;&gt;That is the first point of debate. Are developers uniquely suited to plug those gaps in the system?&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2352&quot;&gt;In a small organization with a few people and 2/3 of the head-count budget locked in software developers, it may feel natural to sidestep the question with another question: “Who else?”. As a manager, no need for further explanation. As a leader, decisions by elimination are rarely part of a sustainable strategy.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;d603&quot;&gt;Let’s examine what part “being on call” plays in that system. Your organization promised the product (not the system) would meet specific service levels. Things falling off the rails in the middle of the night or on weekends cannot stay down until business hours resume the next day or on Monday, so “something” needs to be ready to restore the service levels.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f8d9&quot;&gt;Ideally, that “something” would be an automated process that runs immediately, but there are always problems that cannot be identified or resolved in the same ways.&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;3a9e&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“They are the ones most experienced with our technology stack.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;4110&quot;&gt;That is a partially true statement. During the development of a system, software developers spend considerable time working directly with some system components, but not necessarily with all of them.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;1824&quot;&gt;Suppose someone experienced with the React framework is on-call, and a system outage ultimately originates from a sharding problem in a Mongo database. That personal experience with UI development will not translate into a faster solution unless one argues the next point.&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;d498&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“They are the ones most experienced with technology in general.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3f14&quot;&gt;Another partially true statement. The thinking here is that while system components may differ, a software developer has experience in developing systems, and that experience gives them insights into other systems.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;8e5c&quot;&gt;This line of thinking does lead to a less common argument: anyone with &lt;em class=&quot;markup--em markup--p-em&quot;&gt;previous&lt;/em&gt; experience in developing systems would have similar insights, which opens the door to people who may still contribute to the system in a different role, such as system designers, architects, and managers.&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;3cc4&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Being on-call aligns consequences with [questionable] product-making decisions.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;a649&quot;&gt;This argument is flawed in multiple ways:&lt;/p&gt;&lt;ol class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;0b7d&quot;&gt;The previous sections show how simply being on-call adversely affects people’s health, whether or not the system experiences an outage. In other words, people on-call who consistently make good decisions will still be negatively affected, contrary to the intention of aligning actions and consequences.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;477c&quot;&gt;Eventual outages may not trace directly to a specific design decision, good or bad.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;fa09&quot;&gt;There may be a significant time lag between a decision and its consequence in an outage, so bad decisions may go unnoticed for a long time and maybe never manifest themselves as system outages (such as poor user experience.)&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;ad11&quot;&gt;Other non-developer  team members can also make decisions that have ramified effects leading to a system outage. Some of the worst, most pervasive system problems causing outages relate to organizational issues rather than design decisions.&lt;/li&gt;&lt;/ol&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;ef51&quot;&gt;There is also ample evidence to suggest that people are not the best at changing current behaviors in light of future events. Even after tracing an outage to a questionable decision, there is no guarantee that the people experiencing that connection will make different decisions in the future.&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;5143&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Developers learn more about the system by handling system outages.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;0895&quot;&gt;This thinking is akin to saying you can learn about boxing by going two rounds against Mike Tyson or Floyd Mayweather. Beyond a certain level of challenge, the personal focus quickly turns from self-improvement to survival.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;c486&quot;&gt;During a system outage, the focus is on the system’s survival by restoring it to health. I have seen mixed responses to &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.atlassian.com/incident-management/kpis/error-budget&quot; href=&quot;https://www.atlassian.com/incident-management/kpis/error-budget&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;error-budget&lt;/a&gt; advocates on Twitter arguing for using that budget as an opportunity to learn more about the system, keeping the system down after finding a solution, and collecting more information about the system while it is in a compromised state.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;68a5&quot;&gt;Nevertheless, in a healthy organization, you can learn more by reading well-written incident reports than by troubleshooting random disks getting filled up in the middle of the night. Hopefully, incident reports will contain:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;58df&quot;&gt;Timelines.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;9899&quot;&gt;Initial symptoms.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;557f&quot;&gt;Troubleshooting steps.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;3ebb&quot;&gt;Links to supporting results in web searches.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;47c8&quot;&gt;A list of commands used during the resolution phase.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;bdfc&quot;&gt;Links to downstream issues found and reported during the incident to request more permanent solutions in the codebase.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;29c0&quot;&gt;The corollary quip here is that organizations must be disciplined in handling post-incident analysis, &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;http://www.rtpscrolls.com/search/label/wiyp&quot; href=&quot;http://www.rtpscrolls.com/search/label/wiyp&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;systematically studying problems&lt;/a&gt; in ways that resemble nothing &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.youtube.com/watch?v=Z3znqYcfeCM&quot; href=&quot;https://www.youtube.com/watch?v=Z3znqYcfeCM&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;like this&lt;/a&gt;.&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;0eb6&quot;&gt;&lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Let’s add all people in the org to the on-call rotation to spread the burden.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;5f25&quot;&gt;If something is complicated and unstable to the point where it needs 30 people to share the load of handling its outages, that often means outage resolutions require great skills and insights into the system, which only a few people in the organization will possess.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;6515&quot;&gt;For that reason, I once quipped that a 30-person rotation schedule is a 27-people buffer with a 1-hour delay before calling the only three people who can resolve the outage.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;2325&quot;&gt;Fix the system, get a grip on its TCO, then manage the frequency and intensity of page-outs. Throwing more people at a wobbling system extends the adverse physical and psychological effects across more people, and there is never a good business case for stressing additional parts of the system beyond their limits.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;a961&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;0af0&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;b194&quot;&gt;Placing developers in an on-call rotation is common and expected. However, it should not be the starting point of any conversation on operating profitable and sustainable systems.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;36a2&quot;&gt;While designing any system, the discussions must include the availability and costs of human intervention and aim at reducing or eliminating that type of intervention while also developing the system’s “service points” with high-visibility tracing from symptoms to causes to resolutions. &lt;strong class=&quot;markup--strong markup--p-strong&quot;&gt;A healthy organization must handle human limits more carefully and rigorously than system limits.&lt;/strong&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;19a4&quot;&gt;Systemic failures should be consistently studied and documented to learn and contextualize new system features to keep page-outs rare and manageable.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;dcef&quot;&gt;An operations team (or the operational discipline in organizations where the entire staff co-shares system administration) should have a firm grip on the total cost of ownership and be a prominent final voice in the deployment of system upgrades or new systems.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;3342&quot;&gt;Once an infrequent and well-scoped problem resolution workflow comes out of the entire system design phase, the on-call rotation should include people equipped to recognize limits and error conditions and a clear supporting structure to bring the system back to health.&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;42a6&quot;&gt;Building a system that prioritizes the well-being of people on-call also allows the participation of a wider pool of people who can handle the occasional system failure without knowing the system at the source code level. Enabling that wider pool of participants in the on-call rotation is particularly useful as the system grows and a larger organization requires a dedicated operations team.&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;bdd7&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;h3 class=&quot;graf graf--h3&quot; name=&quot;4609&quot;&gt;References&lt;/h3&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;5ac3&quot;&gt;“How the chance of missing the alarm during an on-call shift affects pre-bed anxiety, sleep and next-day cognitive performance”: &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S0301051118300929&quot; href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S0301051118300929&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;https://www.sciencedirect.com/science/article/abs/pii/S0301051118300929&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;11e1&quot;&gt;Highlights:&lt;/p&gt;&lt;ul class=&quot;postList&quot;&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;1cc1&quot;&gt;Pre-bed anxiety is higher on on-call nights compared with control.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;51ec&quot;&gt;Poorer sleep on on-call nights where the perceived chance of missing the call alarm was high.&lt;/li&gt;&lt;li class=&quot;graf graf--li&quot; name=&quot;2579&quot;&gt;Faster reaction times on days after on-call nights with a low chance of missing the alarm.&lt;/li&gt;&lt;/ul&gt;&lt;p class=&quot;graf graf--p graf--empty&quot; name=&quot;2faf&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;3bf1&quot;&gt;“Effects of On-Call Work on Well-Being: Results of a Daily Survey”: &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://iaap-journals.onlinelibrary.wiley.com/doi/abs/10.1111/j.1758-0854.2012.01075.x&quot; href=&quot;https://iaap-journals.onlinelibrary.wiley.com/doi/abs/10.1111/j.1758-0854.2012.01075.x&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;https://iaap-journals.onlinelibrary.wiley.com/doi/abs/10.1111/j.1758-0854.2012.01075.x&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;f5cf&quot;&gt;Highlight: &lt;em class=&quot;markup--em markup--p-em&quot;&gt;“Flexible work schedules like on-call work have effects on well-being. The mere possibility of being disturbed by calls shows negative consequences, regardless of whether the employees are called in or not.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--empty&quot; name=&quot;4bb7&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;7cef&quot;&gt;“On-call work and physicians’ turnover intention: the moderating effect of job strain”: &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.tandfonline.com/doi/abs/10.1080/13548506.2015.1051061&quot; href=&quot;https://www.tandfonline.com/doi/abs/10.1080/13548506.2015.1051061&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;https://www.tandfonline.com/doi/abs/10.1080/13548506.2015.1051061&lt;/a&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p&quot; name=&quot;50a6&quot;&gt;Highlight: &lt;em class=&quot;markup--em markup--p-em&quot;&gt;“The highest levels of turnover intention were among those who had on-call duties and high level of job strain characterized by high demands and low control opportunities.”&lt;/em&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--empty&quot; name=&quot;e2ca&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p class=&quot;graf graf--p graf--startsWithDoubleQuote&quot; name=&quot;a808&quot;&gt;“On-Call: The definitive guide to running productive and happy on-call teams”: &lt;a class=&quot;markup--anchor markup--p-anchor&quot; data-href=&quot;https://www.atlassian.com/incident-management/on-call/on-call-schedules&quot; href=&quot;https://www.atlassian.com/incident-management/on-call/on-call-schedules&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;https://www.atlassian.com/incident-management/on-call/on-call-schedules&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class=&quot;section section--body&quot; name=&quot;1937&quot;&gt;&lt;div class=&quot;section-divider&quot;&gt;&lt;hr class=&quot;section-divider&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;section-content&quot;&gt;&lt;div class=&quot;section-inner sectionLayout--insetColumn&quot;&gt;&lt;p class=&quot;graf graf--p graf--empty&quot; name=&quot;e898&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/3785323428538881341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2021/09/asking-wrong-question-should-developers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/3785323428538881341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/3785323428538881341'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2021/09/asking-wrong-question-should-developers.html' title='Should (only) developers be on-call?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-2763560957635014451</id><published>2021-05-21T06:00:00.018-07:00</published><updated>2022-01-19T11:51:03.330-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aiops"/><category scheme="http://www.blogger.com/atom/ns#" term="aiops-series"/><category scheme="http://www.blogger.com/atom/ns#" term="gitops"/><category scheme="http://www.blogger.com/atom/ns#" term="mlops"/><category scheme="http://www.blogger.com/atom/ns#" term="observability"/><title type='text'>AI Ops Series - Part 2: dealing with state machines and time</title><content type='html'>&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In the &lt;a href=&quot;https://sourcepatch.blogspot.com/2021/04/ai-ops-series-part-1-observability-and.html&quot; target=&quot;_blank&quot;&gt;first part&lt;/a&gt; of this series, I wrote about the importance of observability and continuous deployment practices for AI Ops. An observability practice must be pervasive across the organization to support all use cases for training AIs. A continuous deployment practice must be responsive and reliable to&amp;nbsp;support frequent deployment and validation of changes recommended by the AI.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In this second part, I explore the topic of state machines, their adverse impact on AI training efforts, and mitigation strategies.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;State of the union of various systems&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;State machines are combinations of system states and rules directing the transition from one state to another. In an IT shop, the more relevant state machines are of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Event-driven_finite-state_machine&quot; target=&quot;_blank&quot;&gt;event-driven&lt;/a&gt; kind, responding to occurrences in the system.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Some state machines are purpose-built, &lt;a href=&quot;https://en.wikipedia.org/wiki/Finite-state_machine&quot; target=&quot;_blank&quot;&gt;finite&lt;/a&gt;, and well-understood, such as online shopping carts, with all the steps involved in keeping track of the customer selections until they hit that &quot;Buy&quot; button.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;However, not all state machines are designed by or visible to the team operating an IT shop. Some of them lurk inside low-level components, known and understood only by the component vendors. Others are formed inside the data center as you plug various systems together. These ad-hoc state machines introduce novel states and transition paths that are often unnoticeable during regular system operation.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS0wegLeAJkhNTJilvsc43jou6gwjGIYck9GAx2nQqdVHyPMAam4m1EPxbWx9ydEwMGVMzsD5PfPHi7HVDP0TlUWsOTAQUKX1Pery5EPJtppFxe0ZOrsUkY3igWg1WG19YjwN25DZYC-2-/s994/ad-hot-state.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;Picture illustrating ad-hoc, unintentional, complex system state&quot; border=&quot;0&quot; data-original-height=&quot;796&quot; data-original-width=&quot;994&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS0wegLeAJkhNTJilvsc43jou6gwjGIYck9GAx2nQqdVHyPMAam4m1EPxbWx9ydEwMGVMzsD5PfPHi7HVDP0TlUWsOTAQUKX1Pery5EPJtppFxe0ZOrsUkY3igWg1WG19YjwN25DZYC-2-/w400-h320/ad-hot-state.png&quot; title=&quot;Combination of stateful systems creates even larger state machines&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The insidious aspect of these &quot;spontaneous&quot; state machines is that their complexity tends to isolate cause and effect behind a seemingly random combination of state transitions. S&lt;/span&gt;tretch that barrier over a sufficiently long time, and no amount of mathematical genius, human or otherwise, will be able to infer any pattern between cause and effect in that system.&amp;nbsp;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;You can tell where this posting is going: Without (recognizable) patterns, there is no AI Ops.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h4&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Butterfly effects: the delayed kind&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Let&#39;s recall the scenario in part 1, where maintenance of firewall rules inadvertently blocked new connections between two endpoints. Changes to firewall rules affect new session requests but not established links, so pre-existing traffic still flows across the wire. That list of established links is part of the internal state maintained by the firewall appliance.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Suppose you asked the network administrators to find unintended side-effects of those changes to the firewall rules by monitoring the traffic between systems. Without knowledge of that internal state, they may arrive at the incorrect conclusion that there is no correlation because they can still see some traffic flowing.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Now stretch that scenario over an extended period. Let&#39;s assume each of those two endpoints hosts one of the pairs in a high-availability database cluster. In this scenario, these two database nodes established their reciprocal link before the network admins accidentally prevented new connections from forming. Imagine that one of these database nodes fails and, upon restart, that database node cannot establish a link to the other node.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Once teams start dealing with that incident, they may be wondering why the failed database node cannot restart since there is no record of recent changes to it. After hours of troubleshooting, both network and database teams finally discover that the action from weeks ago had a deferred impact on the system&#39;s reliability.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;This type of confusion is just one example of the effects of a state machine (hosted inside the firewall appliance) obscuring cause and effect events across system boundaries and time.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Secrets of state&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;With state machines (intended or not) being an integral part of the modern data center, it is crucial to apply strategies that can:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: decimal; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Reduce their size.&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: decimal; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Restrict them to smaller portions of the system.&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: decimal; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Compress their lifecycle into smaller time windows.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;That is not to mean you should go about rearchitecting your entire system to eliminate all your queue servers and distributed caches. Still, you should take a hard look at those types of indirections and reconsider whether more direct flows could achieve the same results.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The following are the lessons I learned over time about managing state, which forms the advice I would give anyone trying to curb system state and make it more manageable for an AI Ops practice. As a bonus, anything that makes your system signals more strongly correlated can also make your system easier to operate. Win, win.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Lesson #1: Reach out for the serverless parts-bin&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;To state the obvious: if a system does not exist, it cannot hold an internal state.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The first approach in reducing the number and complexity of state machines in the system is to consolidate persistent data into fewer components. With the state contained in fewer places, gradually migrate the new state-less systems to a serverless model, which only runs processes long enough to process individual requests.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;With fewer systems holding internal states and other systems not existing long enough to accumulate any state, you will reduce the size of your system-wide state machines as well as their duration over time.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;As one example from an actual project, a team had dozens of servers capable of processing requests that took several minutes each. In some situations, customers could simultaneously send a few hundred requests and then never send anything else for a week. In the meantime, these servers accumulated state while processing the requests and also while sitting idle. Some of it was useful for performance reasons, such as caching the results of large queries to a scientific literature database. Other cached states were less valuable, centered around the virtual machines processing the requests, such as operating system patches, local user tables, log files exhausting disk space, etc.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Now imagine the same system with a couple of stateful servers handling the database interactions and all the customer requests processed in a serverless fashion, with containers being spun up only for the duration of each request,&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The stateful servers can deal with the lengthy database queries and the regrouping of table rows in the responses, while the other permanent servers do not exist anymore.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCAhkOU5p0r5-AK5DBZJxYDNqL8wTrKQhmTTYTZ5KbMQPZ0S5eAfaUy9JrQEfm0aiHiEQi1qPRkBOLjPGO3dTLvKhlha7dGgOTngttVuGEWzRQujKvBqoBf6Ljb41XhGTKplkYw5834jCT/s1376/from-state-to-serverless.png&quot;&gt;&lt;img alt=&quot;Picture illustrating simplified deployment through usage or serverless workloads&quot; border=&quot;0&quot; data-original-height=&quot;578&quot; data-original-width=&quot;1376&quot; height=&quot;269&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCAhkOU5p0r5-AK5DBZJxYDNqL8wTrKQhmTTYTZ5KbMQPZ0S5eAfaUy9JrQEfm0aiHiEQi1qPRkBOLjPGO3dTLvKhlha7dGgOTngttVuGEWzRQujKvBqoBf6Ljb41XhGTKplkYw5834jCT/w640-h269/from-state-to-serverless.png&quot; title=&quot;Concentrate state into fewer systems and move the rest to a serverless model&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Lesson #2: Join the crowds&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Look for products with good documentation and large user bases to increase your understanding of how it behaves. A product or component with an extensive user base tends to have its edge cases explored more often, leading to fixes (better quality) or better documentation (better visibility into those edge cases.)&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;If that sounds a lot like open source, you may be right. Commoditization of components and design patterns means a more predictable system, and predictability is always good whether you are learning something or using the resulting data to train an AI.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;As usual, be mindful of tradeoffs: any new component introduced in a data center brings along its complexity. Ensure you are not replacing a small and obscure corner of the system with something transparent but unwieldy.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;After all, every team has their stories of people bringing in entire queue management systems to handle a handful of messages a day. These teams may also have stories about those queue servers requiring all sorts of unexpected upkeep and monitoring of queue sizes, dead-letter queues, etc.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;h2 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/h2&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; font-size: small; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Lesson #3: State your intentions, declarative over imperative&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;An imperative approach to system configuration describes all steps required to bring the system to the desired state. In contrast, a &lt;a href=&quot;https://en.wikipedia.org/wiki/Declarative_programming&quot; target=&quot;_blank&quot;&gt;declarative&lt;/a&gt; model expresses the expected state of the system without prescribing the control flows needed to get there.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In simpler words, with a declarative approach, you tell the system what you want. In an imperative process, you have to build what you need step-by-step.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The examples of imperative approaches in a data center are scripts written in languages ranging from shell scripting to higher-level abstractions such as &lt;a href=&quot;https://cdk8s.io/&quot; target=&quot;_blank&quot;&gt;cdk8s&lt;/a&gt;. &lt;a href=&quot;https://www.gitops.tech/&quot; target=&quot;_blank&quot;&gt;GitOps&lt;/a&gt; is probably the more visible umbrella for declarative approaches, built atop configuration frameworks like &lt;a href=&quot;https://helm.sh/&quot;&gt;helm&lt;/a&gt;, &lt;a href=&quot;https://kustomize.io/&quot; target=&quot;_blank&quot;&gt;kustomize&lt;/a&gt;, and &lt;a href=&quot;https://jsonnet.org/&quot; target=&quot;_blank&quot;&gt;jsonnet&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQfCAsoZLoioQoF6TDJubLj_Al7UmCEjgbePBLb0UQSb46mUGHPZZErbasksYgLFPBpbLVjAo1pqxS2_berYx5GyolJAIEZGollyMy0wmXGYJOLcdpRyWJEV0OD8p-Ix2yK3-NWGUD40zF/s866/imperative-to-declarative.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;Picture suggesting replacing building materials with blueprints&quot; border=&quot;0&quot; data-original-height=&quot;632&quot; data-original-width=&quot;866&quot; height=&quot;234&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQfCAsoZLoioQoF6TDJubLj_Al7UmCEjgbePBLb0UQSb46mUGHPZZErbasksYgLFPBpbLVjAo1pqxS2_berYx5GyolJAIEZGollyMy0wmXGYJOLcdpRyWJEV0OD8p-Ix2yK3-NWGUD40zF/w320-h234/imperative-to-declarative.png&quot; title=&quot;Declarative approaches are like blueprints&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q: What does any of this have to do with state machines and AI Ops?&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Declarative approaches require system states to be handled by components specialized in bringing the system from an initial state to the desired state, such&amp;nbsp;as&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Event-driven_finite-state_machine&quot;&gt;ArgoCD&lt;/a&gt;, &lt;a href=&quot;https://fluxcd.io/&quot; target=&quot;_blank&quot;&gt;Flux&lt;/a&gt;, and &lt;a href=&quot;https://jenkins-x.io/&quot; target=&quot;_blank&quot;&gt;Jenkins X&lt;/a&gt;. These components have narrower mandates than custom-built code (which pretty much can touch everything) and strive to process the system changes as quickly as possible. They ensure that a request for the system to achieve a given state leads to outputs directly tied to the request both in scope and time.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q: Don&#39;t these components bring their own internal state, thus offsetting the benefits and just moving the original problem elsewhere?&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Yes, they have their state, but it is narrower in scope and in time. They require you to decouple functions that handle state from your other control loops and consolidate those functions into fewer system components. This consolidation reduces the number of architectural and logical)connections between systems and the number and size of system-wide state machines.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;As an extra tip, minimize the use of &quot;escape hatches&quot; in declarative approaches, where you can ask the component processing the requests to execute imperative code blocks before and after each request.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Lesson #4: Always test configuration changes immediately&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;It is challenging to detect patterns between even the most perfectly correlated events when they happen far apart in time. Unless the time windows separating the occurrences is somewhat constant and well-known, or you are pretty good at time series forecasting (see next section,) the chances of finding those patterns become rather slim.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;One common source of delayed reactions in a system is deferred restarts of affected services after configuration changes. As a general rule, whenever the configuration for a component changes, restart all instances of that component, observing high-availability requirements and capabilities of the system. The restart ensures that eventual side effects of those changes manifest themselves sooner instead of the next time the component restarts, like in the earlier example about firewall rules in a network appliance.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;I felt that this lesson might not be as broad as the others in this article. However, the combination of their frequency and chaotic impact on machine learning efforts helped it make it into the list.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Lesson #5: Transforming time&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;After applying all previous lessons, you are still likely to be facing several state machines in the system, which will be in their never-ending march through time. In that time, the system will be producing metrics continuously, generating various &lt;a href=&quot;https://en.wikipedia.org/wiki/Time_series&quot; target=&quot;_blank&quot;&gt;time series&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Finding correlations between the measurements in a time series may be difficult if some metrics reflect the consequences of past events. Even a short time may throw off your correlation attempts. For example, a surge in user requests may take a few minutes to spool up new serverless workloads before generating additional heat and consume extra energy to cool those CPUs.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;You are now solidly in the territory of data science and machine learning, more specifically, time series forecasting. This discipline attempts to transform the data to minimize the impact of time variances. The topic is somewhat dense for this series&#39;s depth, and I plan on covering it with a practical example in a future posting. For now, I recommend a look at this great&amp;nbsp;&lt;a href=&quot;https://towardsdatascience.com/time-series-forecasting-968192b3781a&quot; target=&quot;_blank&quot;&gt;overview article&lt;/a&gt;&amp;nbsp;and, if the subject further interests you, consider a deeper dive into this &lt;a href=&quot;https://machinelearningmastery.com/machine-learning-data-transforms-for-time-series-forecasting/&quot; target=&quot;_blank&quot;&gt;fantastic series of articles on the topic&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Conclusion&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;This part of the series covered the effects of state machines in training efforts for AIs and a few strategies to address those effects. The lessons covered different phases of a system lifecycle:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Architecture: favor&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;serverless&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;workloads over permanent servers.&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Implementation: prefer&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;open source&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;over closed source.&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Deployment: use&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;declarative&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;over imperative approaches for changing the system configuration.&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Operations: restart all components adjacent to a reconfigured system.&lt;/span&gt;&lt;/li&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Optimization: Employ techniques of&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;time series forecasting&lt;/strong&gt;&lt;span style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;to eliminate or reduce the effects of time on the training data.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The theme of the lessons is to reduce the number, complexity, and duration of state machines across the system. The ultimate goal is to have more substantial and more immediate correlations between events and outcomes in the data center before using their data to train AIs.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;h4 style=&quot;text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Coming up next&lt;/strong&gt;&lt;/h4&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In the third part of this series, I will cover the exciting topic of using chaos engineering and unsupervised learning to train machine learning models.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h2 style=&quot;background: transparent; color: #0e101a; font-weight: normal; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/h2&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/2763560957635014451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2021/05/ai-ops-series-part-2-dealing-with-state.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2763560957635014451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2763560957635014451'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2021/05/ai-ops-series-part-2-dealing-with-state.html' title='AI Ops Series - Part 2: dealing with state machines and time'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS0wegLeAJkhNTJilvsc43jou6gwjGIYck9GAx2nQqdVHyPMAam4m1EPxbWx9ydEwMGVMzsD5PfPHi7HVDP0TlUWsOTAQUKX1Pery5EPJtppFxe0ZOrsUkY3igWg1WG19YjwN25DZYC-2-/s72-w400-h320-c/ad-hot-state.png" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>USA</georss:featurename><georss:point>35.6251337 -78.8495889</georss:point><georss:box>7.3148998638211538 -114.0058389 63.935367536178845 -43.6933389</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-405872896464665701</id><published>2021-04-28T11:07:00.027-07:00</published><updated>2022-01-19T11:45:21.994-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ai"/><category scheme="http://www.blogger.com/atom/ns#" term="aiops"/><category scheme="http://www.blogger.com/atom/ns#" term="aiops-series"/><category scheme="http://www.blogger.com/atom/ns#" term="cicd"/><category scheme="http://www.blogger.com/atom/ns#" term="mlops"/><category scheme="http://www.blogger.com/atom/ns#" term="nlp"/><category scheme="http://www.blogger.com/atom/ns#" term="observability"/><title type='text'>AI Ops Series - Part 1: observability and continuous deployment</title><content type='html'>&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;AI Ops is a recurring theme across the industry, with vendors vying for dominance in the application of artificial intelligence across IT operations.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;While there is a&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://thenewstack.io/observability-and-the-misleading-promise-of-aiops/&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;valid criticism of &quot;AI Ops,&quot;&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;often rooted in unrealistic assessments about the potential of anomaly detection, that type of criticism misses the mark on the&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://thenewstack.io/the-next-frontier-for-aiops-application-optimization/&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;usage of AI in every other IT scenario that does not involve finding problems&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;This posting is the first of a series of candid assessments of what is possible and what is not realistic with the current state of the art. The series reflects my experiences designing machine learning pipelines for natural language processing of technical literature and designing the operational practices for a global SaaS platform based on thousands of systems.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Note: I use &quot;Artificial Intelligence&quot; as the umbrella for Natural Language Processing and Machine Learning algorithms throughout this post.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Business intelligence precedes artificial intelligence: observability&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;.&lt;/span&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Before your organization can &quot;hire&quot; an AI to process and act on data, it must ensure it can collect and feed information to that system.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In the operations world, it means taking a hard look at your&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://thenewstack.io/monitoring-vs-observability-whats-the-difference/&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;observability practices&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;and where your team fits in a spectrum ranging from acting on incomplete data to&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://twitter.com/autoletics/status/1378728218174324737&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;situational awareness&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Imperfect observability means your AI can see fewer data types and fewer examples of those data types. The problems can range from technical difficulty in collecting the data to organizational challenges in getting buy-in and approval to transfer the data.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Let&#39;s assume a scenario where an application becomes unresponsive for a few seconds every couple of hours. Your experienced developers ask:&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;I see traffic to the backend getting interrupted, was there any change to the internal network?&quot;&lt;/em&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE-Oy1rMHpgS1BuGxNmAhiuCbKZkiAKDdEjRQ22ESs1Zxoo2_bNcyIbDBUG0QPIKvHGLF3bd_DLJW26HAPAegFsMQtVr5yNg3F2wg436K8OIHqo7j-ER-PIeoqM_8Gg1Bf_vzatZJsLoC5/s1924/network-cut2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;912&quot; data-original-width=&quot;1924&quot; height=&quot;304&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE-Oy1rMHpgS1BuGxNmAhiuCbKZkiAKDdEjRQ22ESs1Zxoo2_bNcyIbDBUG0QPIKvHGLF3bd_DLJW26HAPAegFsMQtVr5yNg3F2wg436K8OIHqo7j-ER-PIeoqM_8Gg1Bf_vzatZJsLoC5/w640-h304/network-cut2.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;To answer that question, you need data about that internal network covering the periods before and after the problem started. The data may even narrow down the time window when the trouble started. You would like to see information such as records of change requests, traffic volumes, network connections, and packet errors.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;An organization with an established observability culture could answer this and many other exploratory questions through queries on a console or&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://youtu.be/h1Hsw1zSens&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;watching live animations of the traffic changes&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;. Without observability telemetry in place, that data-driven process would have to be replaced with experience and (slower)&amp;nbsp;&lt;a href=&quot;http://www.rtpscrolls.com/search/label/problem&quot; target=&quot;_blank&quot;&gt;problem-solving techniques&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;A time for action: continuous deployment&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In that same example of the unresponsive application, let&#39;s say the team narrowed down the problem&#39;s cause to a patch applied to a network firewall rule on the day before the problems started. In an organization with effective&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;continuous deployment practices&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;, it should be possible to test the theory with little effort (minutes) and high precision (closest possible configuration to the production environment).&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIyaYxk-YYb_nhsgMsnwo_LNMO4W5qHudTul0_p9uC3-0V261wNCiIqBSQG3ckDbcm-By_HNlf8kJDkihD7_iH8SUFMqR6fC5CJKsDMs1aMu-LZjaH7cV9eSFoTo9i6HGeCZjl-QncwX0W/s2048/network-cut-full.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1077&quot; data-original-width=&quot;2048&quot; height=&quot;336&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIyaYxk-YYb_nhsgMsnwo_LNMO4W5qHudTul0_p9uC3-0V261wNCiIqBSQG3ckDbcm-By_HNlf8kJDkihD7_iH8SUFMqR6fC5CJKsDMs1aMu-LZjaH7cV9eSFoTo9i6HGeCZjl-QncwX0W/w640-h336/network-cut-full.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Without an established continuous deployment practice, the network team may not be allowed to wait for all your attempts to debug the problem before they need to execute other unrelated change requests to the firewall rules. A new change may either correct or worsen the original problem, triggering another round of troubleshooting under the changed conditions. Additionally, the lack of opportunity to validate a theory can deprive both development and network teams of valuable insight into how the firewall rules affect the system and how to make the overall system more resilient.&lt;br /&gt;&lt;br /&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Human oversight and manual approval of deployments requested by the AI will be the norm at first but plan to move up in the&amp;nbsp;&lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://www.forbes.com/sites/cognitiveworld/2020/05/30/the-autonomous-systems-pattern-of-ai/&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;scale of autonomous systems&lt;/a&gt;&lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;and increasingly delegate independent action to the AI. At that point, your organization should be starting a closer look at developing internal&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://en.m.wikipedia.org/wiki/MLOps&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;ML Ops practices&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;and treating the AI as yet another portion of the running system, with its own CI/CD pipeline and operational processes.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Whereas a&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://copyconstruct.medium.com/testing-in-production-the-safe-way-18ca102d0ef1&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;test in production&quot; strategy&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;is not mandatory, it tends to yield more realistic results when testing out theories about the system and, more importantly, faster rollout and rollback times.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Supervised, unsupervised, or reinforcement learning&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://machinelearningmastery.com/a-tour-of-machine-learning-algorithms/&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;This article&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;has an excellent description of the various training techniques used in machine learning, which I summarize here:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Supervised learning&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;is when you have input and outcome data for a problem. In the previous example about intermittent application crashes, we would have all the data about firewall upgrades, like timestamps, steps performed, and firewall status after the upgrade was complete.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Unsupervised learning&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;is when you only have input data and want the machine to try and cluster the data, detect anomalies, or find associations between the data points. Back to the firewall example, an AI could tell us that the CPU on the network router is 20% over its average within 20 minutes after each upgrade or that the incidence of application crashes is higher within 30 minutes of making changes to firewall rules.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;li style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; list-style-type: disc; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Reinforcement learning&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;is when the system can generate new situations and observe whether it causes good results. Imagine a data center that can vary the output of its cooling units, watch the resulting variation in inlet temperature sensors, and then predict which racks are more prone to failure due to overheating.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;A few words about words: NLP (Natural Language Processing)&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;One of the areas where I spent the most time researching solutions was training an AI to read free-formed text authored by researchers, which tends to be sprinkled with deep contextual references and written without uniform editorial standards.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Time for a pseudo-dialog, where you ask the questions, and I answer them candidly:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q:&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;Can I use AI to read incident reports and tell me what caused them?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;A: No. If you are not an R&amp;amp;D shop, do yourself a favor and move on to the next section.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q: &quot;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;But we do DevOps, so we are an R&amp;amp;D shop!&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;A: That is more of a rebuttal, though I can see you are determined. You have the &quot;D&quot; in R&amp;amp;D, but research in this space is a discipline of its own. I would still move on to the next section.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q:&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;Before I move to the next question, can I at least have an AI cluster the words in incident reports to give me some insight?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;A: It will be fun for a couple of hours. Read this article for some ideas on using a&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://towardsdatascience.com/lovecraft-with-natural-language-processing-part-3-tf-idf-vectors-8c2d4df98621?gi=d09caac3c3f7&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;TF-IDF clustering algorithm&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;and be sure to make a quick stop at&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;http://Wordart.com&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;WordArt&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;to order a mug with the results.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;If you have not moved on to the next section, time for the long answer to this question, which demands that I switch sides with you at the interview table and ask a few questions of my own:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q:&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&quot;Do you have editorial policies for incident report write-ups, comprehensive modeling of attributes for outages, as well as a strong team discipline in filing out these reports?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Take a moment to read through a handful of incident reports written by your team and figure where they fall in the spectrum between shorthand notes and something you would find in a magazine article. If yours is a typical shop, you will find writing akin to a telegram, written when people are tired and not sure anyone will read or act on them.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q:&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&quot;Do you have at least a few hundred examples of these incident reports?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Machine learning algorithms need to process many examples before creating a trained model that can handle a random sample. The number of starting examples may need to be even higher if the examples do not follow any editorial guidelines.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q: &quot;Do you have NLP specialists on hand to create a semantic network? Follow-up question, can you give them months to clean up the input text, deploy a machine learning pipeline, iterate over revised versions of that semantic network, and reshape the input data as they progress?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;If, for some miracle of probability, your answers to all previous questions are still positive, then the final question:&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q: &quot;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Are you willing to retrain a portion of your operations team in NLP techniques, develop a machine learning pipeline, operate said machine learning pipeline, then turn them loose with a non-refundable check with six zeroes in it?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;At that last &quot;yes,&quot; congratulations, you not only have herculean levels of organizational fortitude, but you have got yourself an R&amp;amp;D project in a low-margin OPEX-heavy operation. You are probably part of a large-cap cloud vendor where you can amortize the investment over deployments with tens of thousands of servers. I&#39;ll stand corrected and have fun while reading the whitepapers.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;All right, what&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;can&lt;/span&gt;&lt;/em&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;I do with it?&lt;/span&gt;&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Unsupervised learning&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;is undoubtedly the place to start.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;The simple exercise of tallying up all the data sources in the system will already deliver results and increase your business intelligence. Be prepared for gratifying surprises where even your most seasoned system operators learn new relationships between system components and activities.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;There are many vendor solutions already doing that sort of analysis with data observed from the system and that is the lowest cost of entry.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;There is a long line of products in the space, starting with (in my recollection) Splunk log analysis in the early 2000s and growing into an almost weekly list of new entrants.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Your first candidates should be areas where your system generates a consistent stream of data. The better candidate will form a &quot;&lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://en.m.wikipedia.org/wiki/Closed_set&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;Closed Set&lt;/a&gt;,&lt;/span&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot; otherwise your AI will oblige by telling you there is no strong correlation between any of the values in the data set.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;In layman&#39;s terms, that closed set means your variables are a function of one another and not completely disjointed. In IT terms and going back to the example where the operations team modified a firewall rule, a &quot;Closed Set&quot; would contain data about firewall change requests rather than about&amp;nbsp;something that is not affected by the network at all, such as the hourly temperature in the data center.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q:&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;So, I need to know the correlation beforehand? I wanted the machine to tell me about the correlations.&quot;&lt;/em&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Yes, you need to know the correlations beforehand. Until artificial general intelligence has evolved to human levels of knowledge acquisition and classification, you need to be the one who knows the causal relation between events, or at least the one who has some idea about them.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Do not be disappointed. Your brain is capable of&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;http://psychology.iresearchnet.com/developmental-psychology/cognitive-development/cognitive-equilibrium/#:~:text=Cognitive%20equilibrium%20refers%20to%20a,knowledge%2C%20fit%20with%20new%20knowledge.&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;cognitive equilibrium&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;; AI &quot;brains&quot; are not. Your brain continuously forms a mental model of entities and relationships, classifying new knowledge on top of that mental model and reshaping that model if the classification is not possible. The brain is quite a marvel, indeed, and I wholly recommend a read of&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://books.google.com/books/about/The_Development_of_Thought.html?id=PsM_AQAAIAAJ&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;The Development of Thought: Equilibration of Cognitive Structures&quot;&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;by Jean Piaget to appreciate its complexity.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;I digress, the learning and reasoning abilities of machines are nowhere close to ours, but there is still the&amp;nbsp;&lt;/span&gt;&lt;a class=&quot;editor-rtfLink&quot; href=&quot;https://www.blogger.com/blog/post/edit/3333361346099343040/405872896464665701#&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #4a6ee0; margin-bottom: 0pt; margin-top: 0pt;&quot; target=&quot;_blank&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;Knowledge Discovery&quot;&lt;/span&gt;&lt;/a&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;discipline of machine learning, which allows them to categorize and classify data. Oh, beware of bias.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q:&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;So, you are saying the machine will at least help me find the correlation?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Yes, it will.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Let&#39;s go back to our example of an outage caused by a change to network firewall settings. Suppose you were to feed a machine learning algorithm with a reduced data set, containing metrics about resource utilization and outage information, but without any data about the change requests.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Whereas a machine learning algorithm processing that incomplete data set could not point at the cause of the outages, the statistical analysis could highlight that resource usage in a group of devices decreases by 90% while the system is down. It could also point out that resource usage goes up by 50% in another set of devices. Studying those types of findings increases your understanding of how the system works, which is valuable in itself.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Additionally, the faster you can learn about the lack of strong correlations, the quicker you can rule out invalid assumptions and move on to formulating new theories.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Q:&amp;nbsp;&lt;/span&gt;&lt;em style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&quot;But this is only helping people better understand the system. When does the AI start doing its job and fixing problems?&quot;&lt;/em&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Once again, business intelligence precedes artificial intelligence. The more people understand how the system works and how it evolves, the better your chance of identifying internal processes where the benefit of the AI outweighs the cost of deploying and continuously retraining it.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Initial conclusions&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;We covered the importance of ensuring good practices in IT operations before spending time and energy trying to deploy an AI that can make those operations better.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Your organization will need an&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;observability&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&amp;nbsp;discipline covering all systems supporting your initial scenarios and some level of data science literacy amongst the staff in recognizing and plugging holes in the data coverage.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;You will also need effective&amp;nbsp;&lt;/span&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;continuous deployment&amp;nbsp;&lt;/strong&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;practices to apply the AI&#39;s conclusions to the system and support future autonomy powered by ML Ops.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;span data-preserver-spaces=&quot;true&quot; style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Lastly, AI Ops initially augments your engineering discipline; it does not replace it. Be prepared to develop basic data science data engineering practices in-house, adapt your processes to combine the strengths of humans and AI, and draft a business plan that shows you can offset the investment with savings in operational costs.&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;h4 style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt; text-align: left;&quot;&gt;&lt;strong style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;Coming up next&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; color: #0e101a; margin-bottom: 0pt; margin-top: 0pt;&quot;&gt;&lt;br /&gt;In the &lt;a href=&quot;https://sourcepatch.blogspot.com/2021/05/ai-ops-series-part-2-dealing-with-state.html&quot; target=&quot;_blank&quot;&gt;second part of this series&lt;/a&gt;, I cover the challenging aspect of dealing with the lag between cause and effect in IT events and their impact on the deployment of AI Ops.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/405872896464665701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2021/04/ai-ops-series-part-1-observability-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/405872896464665701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/405872896464665701'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2021/04/ai-ops-series-part-1-observability-and.html' title='AI Ops Series - Part 1: observability and continuous deployment'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE-Oy1rMHpgS1BuGxNmAhiuCbKZkiAKDdEjRQ22ESs1Zxoo2_bNcyIbDBUG0QPIKvHGLF3bd_DLJW26HAPAegFsMQtVr5yNg3F2wg436K8OIHqo7j-ER-PIeoqM_8Gg1Bf_vzatZJsLoC5/s72-w640-h304-c/network-cut2.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-7956694135615415286</id><published>2019-11-14T15:20:00.005-08:00</published><updated>2021-04-29T04:03:43.601-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aad"/><category scheme="http://www.blogger.com/atom/ns#" term="appsody"/><category scheme="http://www.blogger.com/atom/ns#" term="azure"/><category scheme="http://www.blogger.com/atom/ns#" term="containers"/><category scheme="http://www.blogger.com/atom/ns#" term="docker"/><category scheme="http://www.blogger.com/atom/ns#" term="docker-desktop"/><category scheme="http://www.blogger.com/atom/ns#" term="windows"/><category scheme="http://www.blogger.com/atom/ns#" term="windows-10 azure-active-directory"/><title type='text'>Configure Docker Desktop on Windows to run with Azure Active Directory</title><content type='html'>This article is a generalized version of the &lt;a href=&quot;https://appsody.dev/docs/docker-windows-aad/&quot; target=&quot;_blank&quot;&gt;FAQ page&lt;/a&gt; I wrote for &lt;a href=&quot;https://appsody.dev/&quot; target=&quot;_blank&quot;&gt;Appsody&lt;/a&gt;. I should note that my initial searches for a solution invariably led to &lt;a href=&quot;https://tomssl.com/2018/01/11/sharing-your-c-drive-with-docker-for-windows-when-using-azure-active-directory-azuread-aad/&quot; target=&quot;_blank&quot;&gt;this page&lt;/a&gt;, which did not work for me.&lt;br /&gt;
&lt;br /&gt;
Docker Desktop on Windows requires access to the computer&#39;s filesystems to mount host volumes contained in those filesystems. I explain how to grant that access in the &quot;Shared Drives&quot; section of the &lt;a href=&quot;https://docs.docker.com/docker-for-windows/&quot; target=&quot;_blank&quot;&gt;&quot;Get started with Docker for Windows&quot;&lt;/a&gt; page.&lt;br /&gt;
&lt;br /&gt;
If your container relies on mounted hosted volumes, Docker Desktop must be configured to access the shared drive containing those directories. Once Docker has that access, the next requirement is for that user to have the &quot;Full Control&quot; permission to directories mounted to containers. This last requirement is essential if the directory to be mounted resides within the home directory for the Windows user.&lt;br /&gt;
&lt;br /&gt;
It is sufficient to configure Docker with the same user as the current Windows user in most cases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
However, for users of Windows 10 Enterprise secured with Azure Active Directory (AAD), the AAD user does not reside in the local host. That user may not be accepted in the &quot;Shared Drives&quot; tab of the Docker Desktop &quot;Settings&quot; page, especially if the organization has configured AAD to use authentication mechanisms that do not include user passwords, such as PIN codes.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Workaround for Windows 10 Enterprise secured with Azure Active Directory&lt;/h2&gt;
If Docker Desktop does not accept your AAD user and password in the &quot;Shared Drives&quot; tab of the Docker &quot;Settings&quot; panel, or you do not have the password for your user, the only known workaround (I know) is to use a separate, local, Windows account to handle the drive sharing and file permissions.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4645CchXml0p-CFz-qXx811Gga0pXgQ2pC2cAAzA35Z-Urtjzx_6px1BXUIA2co8-K9coHJ415LYXHRky5HbU_5zomUHqRwrLR9dpHW_DxNzEbJ_MnZ4Q9KfU_0GOGzv2kyY8bYQ89dhE/s1600/Screen+Shot+2019-12-13+at+8.53.42+AM.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;924&quot; data-original-width=&quot;1324&quot; height=&quot;446&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4645CchXml0p-CFz-qXx811Gga0pXgQ2pC2cAAzA35Z-Urtjzx_6px1BXUIA2co8-K9coHJ415LYXHRky5HbU_5zomUHqRwrLR9dpHW_DxNzEbJ_MnZ4Q9KfU_0GOGzv2kyY8bYQ89dhE/s640/Screen+Shot+2019-12-13+at+8.53.42+AM.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 1 - Workaround for sharing local folders as mounted volumes inside docker containers when working as an AAD user&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
Assuming the creation of a new user does not violate your organization policies, the workaround is described in Figure 1 and is achieved with the following steps:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://support.microsoft.com/en-us/help/4026923/windows-10-create-a-local-user-or-administrator-account&quot; target=&quot;_blank&quot;&gt;Create a new local user account&lt;/a&gt; on Windows and use that account and the respective password in the &quot;Shared Drives&quot; tab of the Docker Desktop&#39;s &quot;Settings&quot; panel.&lt;br /&gt;&lt;br /&gt;Most systems will have only a single shared drive, labeled &quot;C.&quot; If your &quot;Shared Drives&quot; list shows additional drive letters, make sure you select the label matching the drive letter for the AAD user&#39;s home directory.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;Grant the new user from step 1 the &quot;Full Control&quot; permission to the folders you may want to mount into docker containers. You could use the &quot;Security&quot; tab for each folder properties in the File Explorer application, but the quickest and simplest mechanism is to open a &quot;Command Prompt&quot; and issue the following commands to achieve the same results:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;
REM This has to be the same user applied to the Shared Drive in&lt;br /&gt;
REM Docker Desktop&lt;br /&gt;
set DOCKER_SHARED_DRIVE_USER=Developer&lt;br /&gt;
icacls &quot;c:\directory\to\be\mounted&quot; /grant %DOCKER_SHARED_DRIVE_USER%:(OI)(CI)F&lt;br /&gt;
&lt;/span&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
Note that the user in the &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;DOCKER_SHARED_DRIVE_USER&lt;/span&gt; environment variable must match the user specified in the Docker Desktop &quot;Shared Drives&quot; tab in the first step.&amp;nbsp;

Since the parameters for &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;icacls&lt;/span&gt; specify a recursive authorization, granting the permission to a directory will propagate to all subdirectories of that directory.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Validating the correct permissions&lt;br /&gt;&lt;br /&gt;The command below is a single line, but may look like multiple lines depending on your browser window size. It will run a docker container that creates (and subsequently removes) a directory in each of the directories modified by the&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;icacls&lt;/span&gt;&lt;/span&gt;&amp;nbsp;command. The command will indicate the successful outcome of the validation if the shared drive access and the filesystem permissions are set correctly:
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;

&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;docker run --rm -it -v &quot;c:\directory\to\be\mounted&quot;:/data alpine /bin/sh -c &quot;mkdir /data/test-write-permission &amp;amp;&amp;amp; echo Success; rmdir /data/test-write-permission&quot;
&lt;/span&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
Removing the workaround&lt;/h2&gt;
If you want to revert the Windows filesystem permissions later, open another &quot;Command Prompt&quot; and execute a &lt;span style=&quot;font-size: x-small;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;icacls ... /remove&quot;&lt;/span&gt;&amp;nbsp;&lt;/span&gt;command for each target directory. The operation is recursive and will remove the permissions from subdirectories of those directories as well.&lt;br /&gt;
&lt;br /&gt;
As an example, for the specific instructions on this page, you would execute the following commands:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;set DOCKER_SHARED_DRIVE_USER=Developer&lt;br /&gt;icacls &quot;c:\directory\to\be\mounted&quot; /remove %DOCKER_SHARED_DRIVE_USER%&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/7956694135615415286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2019/11/mounting-volumes-when-using-docker.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/7956694135615415286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/7956694135615415286'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2019/11/mounting-volumes-when-using-docker.html' title='Configure Docker Desktop on Windows to run with Azure Active Directory'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4645CchXml0p-CFz-qXx811Gga0pXgQ2pC2cAAzA35Z-Urtjzx_6px1BXUIA2co8-K9coHJ415LYXHRky5HbU_5zomUHqRwrLR9dpHW_DxNzEbJ_MnZ4Q9KfU_0GOGzv2kyY8bYQ89dhE/s72-c/Screen+Shot+2019-12-13+at+8.53.42+AM.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-5941691058273976998</id><published>2019-10-17T15:02:00.002-07:00</published><updated>2021-04-29T04:07:09.837-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advocate"/><category scheme="http://www.blogger.com/atom/ns#" term="clinical_trials"/><category scheme="http://www.blogger.com/atom/ns#" term="cloud"/><category scheme="http://www.blogger.com/atom/ns#" term="genomics"/><category scheme="http://www.blogger.com/atom/ns#" term="oncology"/><title type='text'>Bioinformatics was awesome, now back to the cloud, which is also awesome</title><content type='html'>September marked the end of my longest tenure working on the same project.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://www.ibm.com/us-en/marketplace/watson-for-genomics&quot; target=&quot;_blank&quot;&gt;Watson for Genomics&lt;/a&gt;&amp;nbsp;received my professional attention for nearly 4 years, and the team was part of my extended remote family during that same time.&lt;br /&gt;
&lt;br /&gt;
I wrote about &lt;a href=&quot;http://sourcepatch.blogspot.com/2015/12/receding-from-clouds-time-to-land.html&quot; target=&quot;_blank&quot;&gt;that transition&lt;/a&gt; at the time, and looking back, I summarize it as&amp;nbsp;a whirlwind of learning and personal growth.&lt;br /&gt;
&lt;br /&gt;
This was a job where you&amp;nbsp;could be discussing, within the same week, AI bias, how human brains processed text, how the human brain could challenge and reevaluate years of learning in minutes, then switch to a discussion on the business and scientific impact of designing new gene panels for oncology tests.&lt;br /&gt;
&lt;br /&gt;
On a few occasions, we would close the day with a debate on cultural and professional differences that made us laugh and sometimes made us cringe at past gaffes.&lt;br /&gt;
&lt;br /&gt;
A &quot;unique experience&quot; does not come close to making justice to this period in my life. Each colleague earned a cherished and permanent spot in my memories. Some became permanent friends.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Learning how we learn&lt;/h3&gt;
My first year was spent as the technical leader for a machine learning project training an artificial intelligence to read clinical trial descriptions and scientific research papers.&lt;br /&gt;
&lt;br /&gt;
Unlike my other previous teams, this was not a typical software development shop. Our language processing specialist was a former surgeon, a couple of the people training the system had a degree in biology, and we had several scientists with a diverse range of advanced degrees in the oncology field.&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhYbgQ2Aaf2m7VBnX_bWcQnitpKpG6d3g866ID6zRZv6puo9aSZSz0DAcWK50Vthi7BlB9P4PPmYcZ-TbEeGqPqLpV2h6sOeBbkoQ7jssMWcyQZtXDu4g3U8pM8SAiTOlLg3WBJNdpgJ2I/s1600/8565611806_c32b8f032c_q.jpg&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;150&quot; data-original-width=&quot;150&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhYbgQ2Aaf2m7VBnX_bWcQnitpKpG6d3g866ID6zRZv6puo9aSZSz0DAcWK50Vthi7BlB9P4PPmYcZ-TbEeGqPqLpV2h6sOeBbkoQ7jssMWcyQZtXDu4g3U8pM8SAiTOlLg3WBJNdpgJ2I/s1600/8565611806_c32b8f032c_q.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;By &lt;a href=&quot;https://flic.kr/p/e3UZYb&quot; target=&quot;_blank&quot;&gt;Thomas&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
My portion of that work was completed within the year: a pipeline that translated raw text into a neural network of relations between medical concepts. This pipeline&amp;nbsp;could also interpret a mini neural query language that would mine facts from the neural network.&lt;br /&gt;
&lt;br /&gt;
Studying human cognition and inference for an entire year (and realizing some people study it for a lifetime), I developed a decidedly non-technical sense of awe for the brilliance of the human brain. Being in awe may be good to shake your preconceptions, but we had to break it down into progressive levels of cognition:&lt;br /&gt;
&lt;br /&gt;
Level 0 - Humans reading natural language and re-encoding knowledge into tables of facts.&lt;br /&gt;
&lt;br /&gt;
Level 1 - Low-level machine assistance, in the form of keyword searches.&lt;br /&gt;
&lt;br /&gt;
Level 2 - Mid-level machine assistance: identify concepts in written text.&lt;br /&gt;
&lt;br /&gt;
Level 3 - Higher level assistance: given a model of concept types connected by relation types amongst concept types, the machine can identify relations between concepts in written text.&lt;br /&gt;
&lt;br /&gt;
Level 4 - Supervised autonomy, the machine is capable of mimicking humans at level 0, with human experts reviewing small samples of the knowledge to ensure safety.&lt;br /&gt;
&lt;br /&gt;
Level 5 - Full autonomy, machines operate at the same level as humans at level 0, at scales that are impossible for humans.&lt;br /&gt;
&lt;br /&gt;
Some of the takeaways: Level 1 is trivial. Level 2 is not. Level 2 may be a commodity when you have billions of training&amp;nbsp;examples, such as classifying images of cats after millions of people posted captioned photos of cats on social media, but medical research papers are nothing like that. They have no editorial standards across publishers, and there is nothing natural about the language, which is more akin to programming code than anything resembling the sanitized 3rd-grade language commonly found in news articles.&lt;br /&gt;
&lt;br /&gt;
Level 3 is where the field gets magical. Think &lt;a href=&quot;https://www.simplypsychology.org/piaget.html&quot; target=&quot;_blank&quot;&gt;Piaget&#39;s Theory of Cognitive Development&lt;/a&gt;. From thoughts to structures, from structures to thoughts. Assimilation and accommodation.&lt;br /&gt;
&lt;br /&gt;
This was the stage where I left the work and moved to the next stage of my participation in the project, while others continued to take the AI forward.&lt;br /&gt;
&lt;h3&gt;
Understand (the data) before you can teach (the machine)&lt;/h3&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
The work in the machine learning pipeline progressed fast, which allowed extra time to be spent on business intelligence outside the sole realm of processing research papers. I recorded some of that work across &lt;a href=&quot;http://sourcepatch.blogspot.com/search/label/clinical_trials?view=flipcard&quot; target=&quot;_blank&quot;&gt;several entries in this blog&lt;/a&gt;, but the entire activity covered much more than clinical trials.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: right;&quot;&gt;
&lt;/div&gt;
Towards the end, we had a set of dashboards that could show the breakdown of genetic alterations per cancer type, producing valuable insights for different audiences, from researchers trying to understand the system performance against different types of cancers to customers getting to know more&amp;nbsp;about the makeup of cases being treated at their institutions.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
Regular interactions with oncology experts often showed that their training gave them unsurpassed knowledge and intuition about their field, but also showed how interactive visualization of data could still help them augment their knowledge. As one of many examples, we had situations where an expert would look at a list of the 20 most common gene alterations found in a set of patients, immediately recognize 19 of them, and walk away wondering about the one they did not expect to see.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;float: right; margin-left: 1em; text-align: right;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyumyjSX9dgM6GuPX-wm44L-GDqm_mW295eSfFAJLG9qiHJyFwR272Ey3SOB3VXAINi6QpwjHcx0veSWWfOklMLTQDebNUt1j1kKOlK5NSk3XKuEt2J1v6AlvMvo9S4GF1Pyk4dF5tER2R/s1600/48687183287_6fa5a5b295_w.jpg&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;267&quot; data-original-width=&quot;400&quot; height=&quot;212&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyumyjSX9dgM6GuPX-wm44L-GDqm_mW295eSfFAJLG9qiHJyFwR272Ey3SOB3VXAINi6QpwjHcx0veSWWfOklMLTQDebNUt1j1kKOlK5NSk3XKuEt2J1v6AlvMvo9S4GF1Pyk4dF5tER2R/s320/48687183287_6fa5a5b295_w.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;By &lt;a href=&quot;https://flic.kr/p/2hbjxmB&quot; target=&quot;_blank&quot;&gt;Ars Electronica&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
The most important lesson (for me) was that developing a system for collecting, visualizing, and statistically processing data is the most valuable investment when creating a system to train an AI... or even humans.&lt;br /&gt;
&lt;br /&gt;
If anyone is about to start an AI project without having spent several months studying the data, that someone is about to spend a lot of time and resources reverse engineering&amp;nbsp;stumbling blocks to the basic math of &lt;a href=&quot;https://en.wikipedia.org/wiki/Strictly_convex_space&quot; target=&quot;_blank&quot;&gt;strictly convex spaces&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
In simpler terms, BI precedes AI.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
When all is said, and everything is done&lt;/h3&gt;
&lt;div&gt;
Four years is a lot of time, and all of my initial goals had been met, including some of the goals I didn&#39;t think I had.&lt;br /&gt;
&lt;br /&gt;
I acquired a basic understanding of genomics, bioinformatics, and the health domain. I also became moderately knowledgeable about machine learning concepts and techniques, developed a new interest for artificial general intelligence, and acquired a fairly advanced applied knowledge of business intelligence techniques, visualization, and statistical processing.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The next stage of expansion of that knowledge was beyond the project scope and market needs. My interest in artificial general intelligence was one or two decades worth of new degrees away, an investment that could not be pursued without close alignment with business needs.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
After a few months of talks, we collectively agreed on me going back to my strengths in core technology, where I could help the company the most, in its strategic push for hybrid clouds. To sum up the situation by anti-paraphrasing Dr. McCoy: (Currently) I am an engineer, not a Doctor (though now I want to eventually become one).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKvot5HFH0lxCT1IvpHrZ6ZWHMR4H9eTlSDwq0PWj7HLRTnCGzQ5Aoj9SdPdRiA21j-_IQKlgx-IWcHiZblAWFKMJt9OFRulodetzvUgSZT51GIQDX8kbVxQtwuegfaKTSUGKlaLEkeP1i/s1600/153829037_ccf6f1223c_w.jpg&quot; style=&quot;clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;300&quot; data-original-width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKvot5HFH0lxCT1IvpHrZ6ZWHMR4H9eTlSDwq0PWj7HLRTnCGzQ5Aoj9SdPdRiA21j-_IQKlgx-IWcHiZblAWFKMJt9OFRulodetzvUgSZT51GIQDX8kbVxQtwuegfaKTSUGKlaLEkeP1i/s1600/153829037_ccf6f1223c_w.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;By &lt;a href=&quot;https://flic.kr/p/eAq1M&quot; target=&quot;_blank&quot;&gt;Anthony Starks&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Starting in September, I began my new role as a content developer and developer advocate for the open-source &lt;a href=&quot;https://kabanero.io/&quot; target=&quot;_blank&quot;&gt;Kabanero&lt;/a&gt; project and the&amp;nbsp;&lt;a href=&quot;https://www.ibm.com/cloud/cloud-pak-for-applications&quot; target=&quot;_blank&quot;&gt;IBM Cloud Pak for Applications&lt;/a&gt;, spending less time writing product code and more time helping developers understand and adopt the technologies in the real world.&lt;br /&gt;
&lt;br /&gt;
On a daily basis, it sometimes means presenting the technology as-is to various audiences, sometimes it means writing focused guidance for a critical use case, sometimes spending a lot of time developing (and testing) workshops for conference attendants,&amp;nbsp;and everything in between. There are some interesting skunkworks projects that break from traditional molds of advocacy, and I hope to be bringing them to reality very soon.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
One of my new colleagues has written a &lt;a href=&quot;https://medium.com/@dewan./what-i-do-as-a-developer-advocate-at-ibm-da2252179f6&quot; target=&quot;_blank&quot;&gt;nice blueprint&lt;/a&gt; for success in this role, which also hints at the kind of awesome people who will be part of this work. I also had the privilege of watching &lt;a href=&quot;https://twitter.com/Silent_Riot5225/status/1183833349502230528?s=20&quot; target=&quot;_blank&quot;&gt;a presentation on developer advocacy&lt;/a&gt;&amp;nbsp;by &lt;a href=&quot;https://twitter.com/cwillycs&quot; target=&quot;_blank&quot;&gt;Cami Willians&lt;/a&gt; at &lt;a href=&quot;https://allthingsopen.org/&quot; target=&quot;_blank&quot;&gt;ATO&lt;/a&gt;, which further elaborated on that blueprint with a clear breakdown of areas of activity.&lt;br /&gt;
&lt;br /&gt;
If &lt;a href=&quot;https://thenewkingmakers.com/&quot; target=&quot;_blank&quot;&gt;developers are the new kingmakers&lt;/a&gt;, I don&#39;t know what that makes us developer advocates, but it may have something to do with helping kings become better kings, so I may order some virtual cards with the title of &quot;Adviser to the Royal Court&quot; or similar.&lt;br /&gt;
&lt;br /&gt;
Back to work.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/5941691058273976998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2019/10/bioinformatics-was-awesome-now-back-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5941691058273976998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/5941691058273976998'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2019/10/bioinformatics-was-awesome-now-back-to.html' title='Bioinformatics was awesome, now back to the cloud, which is also awesome'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhYbgQ2Aaf2m7VBnX_bWcQnitpKpG6d3g866ID6zRZv6puo9aSZSz0DAcWK50Vthi7BlB9P4PPmYcZ-TbEeGqPqLpV2h6sOeBbkoQ7jssMWcyQZtXDu4g3U8pM8SAiTOlLg3WBJNdpgJ2I/s72-c/8565611806_c32b8f032c_q.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-153272538146897451</id><published>2019-04-22T07:58:00.003-07:00</published><updated>2021-05-07T07:53:36.695-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aact"/><category scheme="http://www.blogger.com/atom/ns#" term="analysis"/><category scheme="http://www.blogger.com/atom/ns#" term="analytics"/><category scheme="http://www.blogger.com/atom/ns#" term="clinical_trials"/><category scheme="http://www.blogger.com/atom/ns#" term="dashboard"/><title type='text'>Correlation between completion of clinical trials and conditions in the trials</title><content type='html'>Business Intelligence precedes Artificial Intelligence.&lt;br /&gt;
&lt;br /&gt;
After posting &quot;&lt;a data-id=&quot;2040291887085700834&quot; data-item-type=&quot;post&quot; href=&quot;http://sourcepatch.blogspot.com/2018/03/applying-machine-learning-on-study-of.html&quot; itemprop=&quot;url&quot; rel=&quot;bookmark&quot;&gt;Applying machine learning to the study of clinical trial data&lt;/a&gt;,&quot; I thought about additional features that could help train a prediction engine for the final status of a clinical trial.&lt;br /&gt;
&lt;br /&gt;
At the time, enrollment numbers looked like a promising field. Still, later investigation revealed that the strong correlation between those numbers and clinical trial status was only reliably established as the trial&amp;nbsp;approached completion. That correlation is something I covered in &quot;&lt;a data-id=&quot;8996073070306097486&quot; data-item-type=&quot;post&quot; href=&quot;http://sourcepatch.blogspot.com/2018/04/using-watson-analytics-as-part-of.html&quot; itemprop=&quot;url&quot; rel=&quot;bookmark&quot;&gt;Using Watson Analytics as part of a Machine Learning process&lt;/a&gt;.&quot; The analysis also surfaced &quot;number of facilities&quot; as another study attribute correlated to overall status (see Figure 1). However, it did not visibly increase the rate of success for the prediction engine.&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1ne-8tTUlaedJDe18ocXk_UB5KrlLynWLyoNpoT0Rbfrh46NbJXqHFE30peLtUK6VYDfocC1GkXhUKILHZCvFX-vqQzCmUguuS92QynfRr0cdYFbrXMGOv72tO-fS0PLf95LCvCaCnRC9/s1600/prediction.detail.no.enrollment.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1065&quot; data-original-width=&quot;1600&quot; height=&quot;426&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1ne-8tTUlaedJDe18ocXk_UB5KrlLynWLyoNpoT0Rbfrh46NbJXqHFE30peLtUK6VYDfocC1GkXhUKILHZCvFX-vqQzCmUguuS92QynfRr0cdYFbrXMGOv72tO-fS0PLf95LCvCaCnRC9/s640/prediction.detail.no.enrollment.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 1 - Studies with a single facility, on the left, have higher termination rates (in green) than studies performed across multiple sites.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;b&gt;Conditions under study&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
After experimentation with attributes directly available in the initial data set, it was time to attempt to derive&amp;nbsp;new data to help train machine learning algorithms, starting with the conditions under study.&lt;br /&gt;
&lt;br /&gt;
Some of the characteristics of a condition, such as incidence and mortality, are directly related to the availability of patients meeting enrollment targets. There is also a correlation between the mortality rate for a patient&#39;s condition and the grim reality of those patients not surviving the entire duration of a study. There are less obvious attributes, such as the exclusionary effects of complex eligibility criteria, which may make it difficult to qualify patients even when the patient&#39;s conditions are not rare in themselves.&lt;br /&gt;
&lt;br /&gt;
Before attempting to dive into each of these possibilities, an easier preliminary step was to demonstrate correlation at an aggregate level, using a new attribute that I straightforwardly named &quot;average completion rate for conditions.&quot; The underlying hypothesis is that some conditions may be harder to study than others and that the studies&#39; final status is somewhat correlated to the conditions associated with the study.&lt;br /&gt;
&lt;br /&gt;
The calculation of this new metric for a clinical trial involves two steps: (1) for each condition, calculate the average completion rate for trials where the condition is mentioned, and then (2) for each trial, calculate the average of the metric obtained in the first step across&amp;nbsp;all conditions mentioned in that specific trial (see Figure 2).&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlqOSKcJliy-5r7mRi5D1uHDTYz9tn6AK87LG9YBGZICWZVp6OgqY6yRMWS3cSxivtLQzIrxN5csxhdfGIyMCCuM68lb80LTqe8cVsIvUmBayFZD9pUAUE5c13sEf1wrqCKRJoD1IxTSn1/s1600/aact.condition.average.completion.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;388&quot; data-original-width=&quot;1600&quot; height=&quot;154&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhlqOSKcJliy-5r7mRi5D1uHDTYz9tn6AK87LG9YBGZICWZVp6OgqY6yRMWS3cSxivtLQzIrxN5csxhdfGIyMCCuM68lb80LTqe8cVsIvUmBayFZD9pUAUE5c13sEf1wrqCKRJoD1IxTSn1/s640/aact.condition.average.completion.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 2 - Calculation of &quot;average condition completion ratio for a clinical trial study&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
For those interested in the details, I uploaded the calculation of the metrics to GitHub (&lt;a href=&quot;https://github.com/nastacio/clinical-bi&quot; target=&quot;_blank&quot;&gt;https://github.com/nastacio/clinical-bi/blob/master/docker/aact/docker-entrypoint-initdb.d/init-user-db.sh&lt;/a&gt;), but here are the results:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCpa0jR-uhh0KUQrri5NTElm9ulqxblBm4il5jc18wtypQwWvJd-vkPg42_wjdBtH-5sdkuf87EM0zq9IMznZEiM6ZvZ-cWVgMUKgqs0QYXfLAwylW8DBZNZnzEfQHTbLT5PLnqtkS_eAP/s1600/aact.condition.average.completion-20190401.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;862&quot; data-original-width=&quot;1600&quot; height=&quot;344&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCpa0jR-uhh0KUQrri5NTElm9ulqxblBm4il5jc18wtypQwWvJd-vkPg42_wjdBtH-5sdkuf87EM0zq9IMznZEiM6ZvZ-cWVgMUKgqs0QYXfLAwylW8DBZNZnzEfQHTbLT5PLnqtkS_eAP/s640/aact.condition.average.completion-20190401.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 3 - Completed studies have higher average completion rates for conditions than terminated studies&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
The columns of charts in Figure 3 correspond to each of the outcomes under analysis: completed, terminated, and withdrawn.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
The first row of charts confirmed my assumption about a correlation between clinical trial completion rates (the green dotted line) and specific conditions. Note how the line is consistently higher on completed trials than on terminated trials.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
I also included a second row of charts indicating the number of studies involved in each calculation so that it was easier to keep a perspective of the statistical significance of the calculated values. The low number of trials with the final status of &quot;Withdrawn&quot; made me discard conclusions about those studies.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
The next visualization (Figure 4) is a more detailed view of the bottom values for average completion, where I wanted to find a pattern between the conditions and their relatively low performance in terms of clinical trial final status.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
A quick read of the values on the bar chart on the right surfaced a common pattern, which I later used to colorize the data points to highlight the pattern: the lowest average completion rates in the whole set are associated with cancers. Cancer conditions are identified with an &quot;Is Oncology&quot; value of &quot;1&quot; in that figure.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7K_x6a9ZZ4cLWMQYCLc0-Ov8E5t1b2vH0yHnxciuyOdO6HRUOwpoKBJqjSCYNuV0llK1avMlLbKvalmSHaRbTkq3V_MHTKw0Fn3hCE6SkxgWh89M5pXqaPr_i1mdh2W_4HpN6y6mkM4sP/s1600/aact.condition.average.completion.bottom40.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;880&quot; data-original-width=&quot;1600&quot; height=&quot;352&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7K_x6a9ZZ4cLWMQYCLc0-Ov8E5t1b2vH0yHnxciuyOdO6HRUOwpoKBJqjSCYNuV0llK1avMlLbKvalmSHaRbTkq3V_MHTKw0Fn3hCE6SkxgWh89M5pXqaPr_i1mdh2W_4HpN6y6mkM4sP/s640/aact.condition.average.completion.bottom40.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 4 - Bottom-40 average completion rates for conditions in interventional studies, considering only conditions appearing in 50 or more studies. The bubble chart on the left has a bubble per condition, with the&lt;span style=&quot;font-size: 12.8px;&quot;&gt;&amp;nbsp;size of the bubble representing the number of studies referencing the condition.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
The charts included only conditions appearing in 50 or more studies to reduce the margins of error, but experimentation with higher or lower values did not produce significant changes to the basic shape and contents of the charts.&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
On the opposite side of those numbers, Figure 5 has the equivalent charts for the top-100 highest values for that same average completion rate metric. Note how only two cancers (mesothelioma and gynecologic cancer) make that list, which will require detailed analysis of their own.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNeLrNQe08ZvP8d_8Ael7hGKlj1oavKbnoxHZISPqgC-IyuV4jKkawUUK_DwocUCSuPx60urMkCHC6A6O0re0cTLM8laNHWkti2jyyG4P-WetHcFsIM_Z3HuteEn8tRuMElFCXxfKHHX7s/s1600/aact.condition.average.completion.to100.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;883&quot; data-original-width=&quot;1600&quot; height=&quot;352&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNeLrNQe08ZvP8d_8Ael7hGKlj1oavKbnoxHZISPqgC-IyuV4jKkawUUK_DwocUCSuPx60urMkCHC6A6O0re0cTLM8laNHWkti2jyyG4P-WetHcFsIM_Z3HuteEn8tRuMElFCXxfKHHX7s/s640/aact.condition.average.completion.to100.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 5 - Top-100&amp;nbsp;average completion rates for conditions in interventional studies, considering only conditions appearing in 50 or more studies.&amp;nbsp;&lt;span style=&quot;font-size: 12.8px;&quot;&gt;The bubble chart on the left has a bubble per condition, with the&lt;/span&gt;&lt;span style=&quot;font-size: 12.8px;&quot;&gt;&amp;nbsp;size of the bubble representing the number of studies referencing the condition.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
In conclusion, this preliminary data confirms the initial intuition that characteristics of the conditions correlate with the outcome of studies. These initial findings warrant more investigation before drawing conclusions, especially in terms of normalizing condition names and drawing further attributes from those conditions, which often included qualifying terms such as &quot;advanced,&quot; &quot;stage III,&quot; &quot;mild,&quot; and others.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/153272538146897451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2019/04/correlation-between-completion-of.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/153272538146897451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/153272538146897451'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2019/04/correlation-between-completion-of.html' title='Correlation between completion of clinical trials and conditions in the trials'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1ne-8tTUlaedJDe18ocXk_UB5KrlLynWLyoNpoT0Rbfrh46NbJXqHFE30peLtUK6VYDfocC1GkXhUKILHZCvFX-vqQzCmUguuS92QynfRr0cdYFbrXMGOv72tO-fS0PLf95LCvCaCnRC9/s72-c/prediction.detail.no.enrollment.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-8233239972440673896</id><published>2018-09-11T16:06:00.002-07:00</published><updated>2019-01-04T07:39:50.363-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="analytics"/><category scheme="http://www.blogger.com/atom/ns#" term="clinical_trials"/><category scheme="http://www.blogger.com/atom/ns#" term="cloud"/><category scheme="http://www.blogger.com/atom/ns#" term="cognos"/><category scheme="http://www.blogger.com/atom/ns#" term="dashboard"/><category scheme="http://www.blogger.com/atom/ns#" term="embedded"/><title type='text'>Clinical Trials visualization with Cognos Dashboard Embedded in the IBM Cloud</title><content type='html'>&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;Disclaimer: I am a software engineer at IBM with access to multiple IBM products, and wrote the content mostly as personal notes to share with a larger team. That said, *as of writing of this entry*, the content mentioned here can be hosted and accessed for free in the IBM Cloud, provided that you do not start more than 50 dashboard sessions per month.&amp;nbsp;&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
Cognos Analytics is IBM&#39;s flagship data visualization tool and has been my companion in charting business intelligence and data insights for the &lt;a href=&quot;https://www.ibm.com/watson/health/oncology-and-genomics/genomics/&quot; target=&quot;_blank&quot;&gt;Watson for Genomics&lt;/a&gt; cloud offering for the past 15 months.&lt;br /&gt;
&lt;br /&gt;
Recently, IBM has launched&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://www.ibm.com/blogs/bluemix/2018/05/introducing-ibm-cognos-dashboard-embedded/&quot; target=&quot;_blank&quot;&gt;Cognos Dashboard Embedded&lt;/a&gt;, a lightweight alternative&amp;nbsp;to the hosted&amp;nbsp;&lt;a href=&quot;https://www.ibm.com/products/cognos-analytics&quot; target=&quot;_blank&quot;&gt;Cognos Analytics on Cloud&lt;/a&gt; product, and I wondered whether that cloud-native approach could be useful for a practical scenario involving a large database.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;b&gt;The domain&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I have been doing a lot of side work with clinical trial visualizations this year, which I consider a data-rich field that can benefit greatly from even the mildest efforts to represent the data in aggregate form.&lt;br /&gt;
&lt;br /&gt;
I had written before about how to load the excellent &lt;a href=&quot;https://aact.ctti-clinicaltrials.org/&quot; target=&quot;_blank&quot;&gt;AACT database&lt;/a&gt; into the IBM Cloud, as a &lt;a href=&quot;http://sourcepatch.blogspot.com/2018/02/deploying-aggregate-analysis-of.html&quot; target=&quot;_blank&quot;&gt;Docker container running the Postgresql dump of AACT&lt;/a&gt;. Later I wrote about using that database &lt;a href=&quot;http://sourcepatch.blogspot.com/2018/03/applying-machine-learning-on-study-of.html&quot; target=&quot;_blank&quot;&gt;to power a predictive engine for clinical trial completion&lt;/a&gt;. I also wrote about how to use &lt;a href=&quot;http://sourcepatch.blogspot.com/2018/04/using-watson-analytics-as-part-of.html&quot; target=&quot;_blank&quot;&gt;Watson Analytics&lt;/a&gt;&amp;nbsp;to obtain insights from a subset of clinical trial data, and then quickly create useful visualizations from that data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The technical bits&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
If you want to replicate this dashboard on your own, you will need a few things:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;An account in the IBM Cloud (&lt;a href=&quot;https://console.bluemix.net/&quot;&gt;https://console.bluemix.net&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Create an database warehouse containing the data, a more involved process described in detail in &lt;a href=&quot;http://sourcepatch.blogspot.com/2018/09/transferring-data-from-the-aact.html&quot; target=&quot;_blank&quot;&gt;this other blog entry&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a Cognos Dashboard Embedded service instance. It is a simple step described in this posting.&lt;/li&gt;
&lt;li&gt;Attach the two services to the application sample created for this entry, which is posted on github:&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/cognos-de&quot;&gt;https://github.com/nastacio/cognos-de&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
Assuming you took care of steps #1 and #2, the following sequence of commands will give you a running application that can render a dashboard of clinical trials studies.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; # clone and build the application, you should have git, a JDK, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # and Maven installed&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; git clone https://github.com/nastacio/cognos-de.git&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; cd cognos-de&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; mvn package&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Push the application to the IBM cloud&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Note the --random-route parameter, which means the IBM Cloud&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # will pick the URL for the application automatically and display&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # it once the application push is complete&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Also note the --no-start parameter, as we don&#39;t want the &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # application to start just yet.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ibmcloud app push cognos-de -p target/cognos-de.war -m 256M -b liberty-for-java --random-route --no-start &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Create the Cognos service instance.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ibmcloud resource service-instance-create ctgov-cognos-de dynamic-dashboard-embedded lite us-south&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ibmcloud resource service-alias-create ctgov-cognos-de --instance-name ctgov-cognos-de -s dev&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Bind the 2 service instances to the application&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Note that the DB2 Warehouse instance will have been created according to&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # http://sourcepatch.blogspot.com/2018/09/transferring-data-from-the-aact.html&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ibmcloud service bind cognos-de ctgov-cognos-de &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ibmcloud service bind cognos-de ctgov-db&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; # Start the application&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ibmcloud app start cognos-de &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Once the application is started, you should see the following output, with the &quot;routes&quot; parameter indicating the URL for your own application:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; name:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cognos-de&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; requested state:&amp;nbsp;&amp;nbsp; started&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; instances:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1/1&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; usage:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 256M x 1 instances&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; routes:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cognos-de-active-grysbok.mybluemix.net&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; last uploaded:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Tue 11 Sep 17:38:22 EDT 2018&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; stack:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cflinuxfs2&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; buildpack:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; liberty-for-java&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; start command:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .liberty/initial_startup.rb&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; state&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; since&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cpu&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; memory&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; disk&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; details&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; #0&amp;nbsp;&amp;nbsp; running&amp;nbsp;&amp;nbsp; 2018-09-11T21:42:04Z&amp;nbsp;&amp;nbsp; 159.9%&amp;nbsp;&amp;nbsp; 132.9M of 256M&amp;nbsp;&amp;nbsp; 208M of 1G&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;b&gt;The building of the dashboard&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
I relied on the &lt;a href=&quot;https://console.bluemix.net/docs/services/cognos-dashboard-embedded/index.html&quot; target=&quot;_blank&quot;&gt;main documentation&lt;/a&gt; and tried to stick to it for the most part. It does a fair job of guiding users from the beginning, though it understandably focuses on getting &lt;i&gt;a&lt;/i&gt; dashboard up and running versus the dashboard you would probably like to build.&lt;br /&gt;
&lt;br /&gt;
I like the idea of their &lt;a href=&quot;https://dde-us-south.analytics.ibm.com/daas/DashboardAPI.html&quot; target=&quot;_blank&quot;&gt;interactive web page&lt;/a&gt;, from where you can see the Javascript required for building an application containing the dashboard, and then bring up the editor on the right side of the screen. Non-technical users will be quickly discouraged between the tutorial and the expectation of a few trips to web consoles, dealing with JSON payloads, table models and others. For those users, the best approach for a user-friendly experience with Cognos is still &lt;a href=&quot;https://www.ibm.com/products/cognos-analytics&quot; target=&quot;_blank&quot;&gt;Cognos Analytics on Cloud&lt;/a&gt; or the &lt;a href=&quot;https://www.ibm.com/cloud/watson-studio&quot; target=&quot;_blank&quot;&gt;Watson Studio&lt;/a&gt; product.&lt;br /&gt;
&lt;br /&gt;
If you are building a dashboard that relies on a hosted database, then you will inevitably have to muscle through the creation of a long JSON file containing &lt;a href=&quot;https://console.bluemix.net/docs/services/cognos-dashboard-embedded/working_with_datasources.html#jdbc-data-sources&quot; target=&quot;_blank&quot;&gt;the metadata for that database&lt;/a&gt;. After you create a new dashboard in the interactive page and then add the data source to it, you can finally use the graphical editor to pull widgets into the page and associate table columns to those widgets.&lt;br /&gt;
&lt;br /&gt;
Once you are satisfied with the results, it is time to issue the &quot;Get the dashboard spec&quot; Javascript call from the web console, and then get a copy of the dashboard spec for later use with the &quot;Open dashboard call&quot;.&lt;br /&gt;
&lt;br /&gt;
Overall, the service works as advertised and offers a powerful set of visualization at a low overall cost of ownership, but the lack of the &quot;Properties&quot; tab in the editor is a glaring omission in what should be a complete graphical package. That tab, present in the final product, is what allows the dashboard designer to customize most of the visual&amp;nbsp; aspects of the widgets on the page, such as the display of axis labels, titles, overlay values, color palettes, and background colors.&lt;br /&gt;
&lt;br /&gt;
My workaround came in the form of having access to a similar dashboard spec from a hosted version of another dashboard, which I used to reverse-engineer the JSON values required to set borders and titles on the widgets. Most system integrators would not have access to such a &quot;donor&quot; file or would be somewhat reluctant to make changes that are not in the official documentation for Cognos Dashboard Embedded.&lt;br /&gt;
&lt;br /&gt;
You can see the final specification for the dashboard at&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/cognos-de/blob/master/src/main/resources/dashboard-spec.json&quot;&gt;https://github.com/nastacio/cognos-de/blob/master/src/main/resources/dashboard-spec.json&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Update on 9/14: My colleague, David Murrels, pointed me at this other project for a &lt;a href=&quot;https://github.ibm.com/dap/cognos-dashboard-component&quot; target=&quot;_blank&quot;&gt;React component for Cognos Dashboard Embedded&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;b&gt;The dashboard itself&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
I focused primarily on representing the progression of studies over the years (by starting date), with breakdowns by study type, overall status, phase, and conditions. I also added a number of dashboard filters at the top, so that it was possible to apply global filtering criteria, such as oncology-related trials or trials from a specific sponsor.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1qLu8GEsd3eQNPO7Qg5js_YYVqB9F4b81sh8KZe53CZwCxjjCiZJyV9Kqz-y8HpEpjHFhR3LP_p6Obsj9UJ2MXGK_YDvYAwtbR6VZ0LQabqwQuZ8dP4GeKRT4YryWGrvCABtRYTnyULTp/s1600/dashboard-screenshot.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;986&quot; data-original-width=&quot;1600&quot; height=&quot;394&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1qLu8GEsd3eQNPO7Qg5js_YYVqB9F4b81sh8KZe53CZwCxjjCiZJyV9Kqz-y8HpEpjHFhR3LP_p6Obsj9UJ2MXGK_YDvYAwtbR6VZ0LQabqwQuZ8dP4GeKRT4YryWGrvCABtRYTnyULTp/s640/dashboard-screenshot.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
I am thoroughly impressed with the overall performance for the Cognos and DB2 Warehouse combo. Even complex combinations of selections on the screen, involving 4 dimensions and multiple selections within those dimensions, rendered smoothly without any kind of delay. Granted, there are only 900K rows in that database, but it is remarkable for a freemium entry plan running on a shared server instance.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoUzoZxuhuWmEtLu6Tslk1hz29edjaoxDl8oUgMovu5F3lSDsh667MKUHtl6tGuC3vFghL2YmpbgBbHLSooXIfHQra-ffepXaA7iZiGTdOwG14mRIY5uT0VwCSKyTFd9opk8b2Qdx8D9NH/s1600/dashboard-1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;993&quot; data-original-width=&quot;1600&quot; height=&quot;396&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoUzoZxuhuWmEtLu6Tslk1hz29edjaoxDl8oUgMovu5F3lSDsh667MKUHtl6tGuC3vFghL2YmpbgBbHLSooXIfHQra-ffepXaA7iZiGTdOwG14mRIY5uT0VwCSKyTFd9opk8b2Qdx8D9NH/s640/dashboard-1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9); min-height: 14.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #34bc26; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
span.s2 {font-variant-ligatures: no-common-ligatures; color: #34bbc8}
&lt;/style&gt;&lt;br /&gt;
&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9); min-height: 14.0px}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #34bc26; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
span.s2 {font-variant-ligatures: no-common-ligatures; color: #34bbc8}
&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
span.s2 {font-variant-ligatures: no-common-ligatures; color: #34bc26}
&lt;/style&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/8233239972440673896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2018/09/clinical-trials-visualization-with.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/8233239972440673896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/8233239972440673896'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2018/09/clinical-trials-visualization-with.html' title='Clinical Trials visualization with Cognos Dashboard Embedded in the IBM Cloud'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1qLu8GEsd3eQNPO7Qg5js_YYVqB9F4b81sh8KZe53CZwCxjjCiZJyV9Kqz-y8HpEpjHFhR3LP_p6Obsj9UJ2MXGK_YDvYAwtbR6VZ0LQabqwQuZ8dP4GeKRT4YryWGrvCABtRYTnyULTp/s72-c/dashboard-screenshot.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-2569702665743807494</id><published>2018-09-11T10:46:00.002-07:00</published><updated>2020-05-12T07:47:03.221-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="analytics"/><category scheme="http://www.blogger.com/atom/ns#" term="clinical_trials"/><category scheme="http://www.blogger.com/atom/ns#" term="cloud"/><category scheme="http://www.blogger.com/atom/ns#" term="cognos"/><category scheme="http://www.blogger.com/atom/ns#" term="db2"/><category scheme="http://www.blogger.com/atom/ns#" term="warehouse"/><title type='text'>Transferring data from the AACT database to a DB2 Warehouse cloud instance</title><content type='html'>This post was written as a technical deep dive into the analytics database referenced in the entry titled &lt;a href=&quot;http://sourcepatch.blogspot.com/2018/09/clinical-trials-visualization-with.html&quot; target=&quot;_blank&quot;&gt;&quot;Clinical Trials visualization with Cognos Dashboard Embedded services in the IBM Cloud&quot;&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The specific choice of database was not central to that posting, but the performance characteristics of the database were an important consideration to achieve good performance. Whereas a transactions-oriented database may be adequate for a dashboard containing a handful of widgets displaying a small data set, heavier utilization of larger data sets often require a standalone warehouse tuned for analytic workloads.&lt;br /&gt;
&lt;br /&gt;
Cognos Dashboard Embedded&#39;s architecture delegates data storage to embedding applications, which allows the choice of using&amp;nbsp;&lt;a href=&quot;https://console.bluemix.net/docs/services/cognos-dashboard-embedded/working_with_datasources.html#working-with-data-sources&quot; target=&quot;_blank&quot;&gt;connections to relational databases or specifying CSV files&lt;/a&gt;. The limit for CSV file sizes is a generous 1 GB, but that also means you need to host the file in a URL-accessible location, while also potentially facing warm up costs for the Cognos backend infrastructure to download, process, and cache the file. In my previous experiences with Cognos and CSV files, the performance for such approach was not that great once the files got past 100 MB in size.&lt;br /&gt;
&lt;br /&gt;
With AACT being available as a&amp;nbsp;&lt;a href=&quot;https://aact.ctti-clinicaltrials.org/connect&quot; target=&quot;_blank&quot;&gt;Postgresql database hosted on the cloud&lt;/a&gt;, one would think that option would be an immediate fit, but I quickly realized two major impediments that forced me to abandon that idea very early in the prototype:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Cognos Dashboard Embedded does not offer the Data Modeling view available in the full Cognos Analytics product, which prevented any possibility of joining the various tables by study identifier. Since I wanted to be able to navigate from studies to conditions and interventions, I could not use the AACT multi-table database structure in its standard topology.&lt;/li&gt;
&lt;li&gt;Postgresql is never tuned for data analytics right out of the box and the AACT cloud database is no exception. You will not notice it for most workloads where you are running moderately complex SQL queries, but dashboard demands are unforgiving between their initial swarm of queries to populate an initial view, the subsequent wince-inducing WHERE clauses created by ad-hoc screen selections, and the end-user expectations that these queries&amp;nbsp;will be serviced instantaneously to result in a fluid experience.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
At this point, the solution looked a bit daunting: use the&amp;nbsp;&lt;a href=&quot;https://console.bluemix.net/catalog/services/db2-warehouse&quot; target=&quot;_blank&quot;&gt;DB2 Warehouse&lt;/a&gt;&amp;nbsp;service in the IBM Cloud, which meant converting the relevant portions of the AACT psql dump to a DB2 table.&lt;br /&gt;
&lt;br /&gt;
As it turns out, a bit of research showed that the DB2 Warehouse offered a complete (and outrageously large) Docker-based client that I could augment with a postgresql client, then use a long string of shell scripting to load the warehouse with the results of a query against the AACT database.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
That&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/clinical-bi/tree/master/docker/db2wh&quot; target=&quot;_blank&quot;&gt;augmented client&lt;/a&gt;&amp;nbsp;is posted to github.com, as well as the&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/clinical-bi/blob/master/docker/db2wh/scripts/db2wh-etl.sh&quot; target=&quot;_blank&quot;&gt;data transfer script&lt;/a&gt;. The data is loaded from 4 different tables: studies, conditions, calculated_values and interventions, then merged into a single table in the warehouse.&lt;br /&gt;
&lt;br /&gt;
Assuming you have the &lt;a href=&quot;https://console.bluemix.net/docs/cli/index.html&quot; target=&quot;_blank&quot;&gt;IBM Cloud CLI&lt;/a&gt;, git and docker installed, these would be the setup steps for the warehouse instance and the final activation for the data transfer:&lt;br /&gt;
&lt;blockquote&gt;
&lt;pre&gt;git clone https://github.com/nastacio/clinical-bi.git
cd clinical-bi/docker/build

mkdir -p ~/etc

# Update on 12/13/2020: The DB2 Warehouse cloud instances no longer have a 
# free plan, so you can use these instructions to create a simple DB2 instance
# which still has a free plan
cloud_region=us-south
ibmcloud resource service-instance-create ctgov-db  dashdb-for-transactions free ${cloud_region} -g default
ibmcloud resource service-key-create ctgov-key --instance-name ctgov-db

# The next instructions are common for either DB2 offering
ibmcloud resource service-key ctgov-key -g default --output json  &amp;gt; ~/etc/db2wh.aact.credentials.json


...

# This may take a few minutes, as there are roughly 5GB worth of data 
# and libraries to be downloaded

docker-compose up -d aact db2wh
docker-compose logs -f &amp;amp;&amp;nbsp;

# wait for the aact database to report being ready to receive connections, 
# it may take a few minutes;
...
db2wh_1          | #######################################################################
db2wh_1          | ###  IBM Db2 Warehouse client container was deployed successfully   ###
db2wh_1          | #######################################################################
...
aact_1           | LOG:  database system was shut down at 2018-09-10 22:21:05 UTC
aact_1           | LOG:  MultiXact member wraparound protections are now enabled
aact_1           | LOG:  database system is ready to accept connections
aact_1           | LOG:  autovacuum launcher started
...

# finally, execute the transfer command

docker-compose exec db2wh /usr/local/bin/db2wh-etl.sh

&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;br /&gt;
If everything goes well, you should see an output like this:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
&lt;pre&gt;INFO: Validating DB2 connectivity parameters

===============================================================================
db2cli writecfg completed successfully.
===============================================================================


===============================================================================
db2cli writecfg completed successfully.
===============================================================================


===============================================================================
db2cli writecfg completed successfully.
===============================================================================


===============================================================================
Client information for the current copy:
===============================================================================

Client Package Type       : IBM Data Server Client
Client Version (level/bit): DB2 v11.1.3.3 (s1803021700/64-bit)
Client Platform           : Linux/X8664
Install/Instance Path     : /opt/ibm/db2/V11.1
DB2DSDRIVER_CFG_PATH value:
db2dsdriver.cfg Path      : /mnt/clientdir/clienthome/db2inst1/sqllib/cfg/db2dsdriver.cfg
DB2CLIINIPATH value       :
db2cli.ini Path           : /mnt/clientdir/clienthome/db2inst1/sqllib/cfg/db2cli.ini
db2diag.log Path          : /mnt/clientdir/clienthome/db2inst1/sqllib/db2dump/db2diag.log

===============================================================================
db2dsdriver.cfg schema validation for the entire file:
===============================================================================

Success: The schema validation completed successfully without any errors.

===============================================================================
db2cli.ini validation for data source name &quot;aact&quot;:
===============================================================================

Note: The validation utility could not find the configuration file db2cli.ini. 
The file is searched at 
&quot;/mnt/clientdir/clienthome/db2inst1/sqllib/cfg/db2cli.ini&quot;.

===============================================================================
db2dsdriver.cfg validation for data source name &quot;aact&quot;:
===============================================================================

[ Parameters used for the connection ]

Keywords                  Valid For     Value
---------------------------------------------------------------------------
DATABASE                  CLI,.NET,ESQL BLUDB
HOSTNAME                  CLI,.NET,ESQL dashdb-entry-yp-dal10-01.services.dal.bluemix.net
PORT                      CLI,.NET,ESQL 50001
SECURITYTRANSPORTMODE     CLI,.NET      SSL

===============================================================================
Connection attempt for data source name &quot;aact&quot;:
===============================================================================

[SUCCESS]

===============================================================================
The validation is completed.
===============================================================================

INFO: Extracting CTGOV dashboard data.
INFO: Creating DB2 Warehouse table.
IBM DATABASE 2 Interactive CLI Sample Program
(C) COPYRIGHT International Business Machines Corp. 1993,1996
All Rights Reserved
Licensed Materials - Property of IBM
US Government Users Restricted Rights - Use, duplication or
disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
&amp;gt; CREATE TABLE CTGOV (NCT_ID VARCHAR(16),OVERALL_STATUS VARCHAR(64),...
The SQL command completed successfully.
&amp;gt;
Loading messages into DB2 warehouse at dashdb-entry-yp-dal10-01.services.dal.bluemix.net. Logs being written at [/mnt/clientdir/clienthome/db2inst1/workdir/load.log]

   Database Connection Information

 Database server        = DB2/LINUXX8664 11.1.9.0
 SQL authorization ID   = DASH5396
 Local database alias   = BLUDB


Number of rows read         = 909432
Number of rows skipped      = 0
Number of rows loaded       = 909432
Number of rows rejected     = 0
Number of rows deleted      = 0
Number of rows committed    = 909432


DB20000I  The SQL command completed successfully.
DB20000I  The TERMINATE command completed successfully.
&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
And you should see a storage utilization around 5% in the service instance dashboard in the IBM Cloud console:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_JRKmp4BE8zT6-vPZ4xYF798rL3AHJoqe-7Lx0i8G9AjL8eYWG_VumD4eXzzM13JT7u2qgrswjNmXEEH0UT_ubC0h21pyQA6E1M8ZXsS-vaAR2-5w0Hegqtkxdle78ELJtqyJvlZRgZu0/s1600/ibmcloud-dashdb.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;736&quot; data-original-width=&quot;1600&quot; height=&quot;292&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_JRKmp4BE8zT6-vPZ4xYF798rL3AHJoqe-7Lx0i8G9AjL8eYWG_VumD4eXzzM13JT7u2qgrswjNmXEEH0UT_ubC0h21pyQA6E1M8ZXsS-vaAR2-5w0Hegqtkxdle78ELJtqyJvlZRgZu0/s640/ibmcloud-dashdb.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;color: black; font-family: times; font-size: medium;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/2569702665743807494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2018/09/transferring-data-from-the-aact.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2569702665743807494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2569702665743807494'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2018/09/transferring-data-from-the-aact.html' title='Transferring data from the AACT database to a DB2 Warehouse cloud instance'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_JRKmp4BE8zT6-vPZ4xYF798rL3AHJoqe-7Lx0i8G9AjL8eYWG_VumD4eXzzM13JT7u2qgrswjNmXEEH0UT_ubC0h21pyQA6E1M8ZXsS-vaAR2-5w0Hegqtkxdle78ELJtqyJvlZRgZu0/s72-c/ibmcloud-dashdb.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-8996073070306097486</id><published>2018-04-01T18:14:00.001-07:00</published><updated>2018-07-24T17:06:40.996-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aact"/><category scheme="http://www.blogger.com/atom/ns#" term="clinical_trials"/><category scheme="http://www.blogger.com/atom/ns#" term="statistics"/><category scheme="http://www.blogger.com/atom/ns#" term="watson_analytics"/><title type='text'>Using Watson Analytics as part of a Machine Learning process</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
Machine Learning often boils down to detecting patterns ... if there are any to be found.&lt;br /&gt;
&lt;br /&gt;
Though we want the machine to do the heavy lifting in detecting and reusing the patterns, we also need to understand the domain and its data in order to choose the features for the training. That understanding is equally crucial to determine whether the data is correct and complete in the first place.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEQHeNLF8_ySo0Xlqrlmn5EcCQDpNgbQbN2t4g6QBi3S3F7Skfu4Yoqw0l90iZMuEFycxoGXR-FdNYvn10Hya7h_dAgnJO6DUo4ckjo_dh9DXEfR1GPa4Fw5Gtip0fWlIPY4iN0NGC-olM/s1600/excel.pivot.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1600&quot; data-original-width=&quot;1485&quot; height=&quot;200&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEQHeNLF8_ySo0Xlqrlmn5EcCQDpNgbQbN2t4g6QBi3S3F7Skfu4Yoqw0l90iZMuEFycxoGXR-FdNYvn10Hya7h_dAgnJO6DUo4ckjo_dh9DXEfR1GPa4Fw5Gtip0fWlIPY4iN0NGC-olM/s200/excel.pivot.png&quot; width=&quot;185&quot; /&gt;&lt;/a&gt;Before getting into the main topic, I admit to being prone to using &lt;a href=&quot;https://support.office.com/en-us/article/overview-of-pivottables-and-pivotcharts-527c8fa3-02c0-445a-a2db-7794676bce96&quot; target=&quot;_blank&quot;&gt;PivotTables&lt;/a&gt; in MS-Excel when trying to understand the interplay between different columns in a data set.&lt;br /&gt;
&lt;br /&gt;
I know there are strong opinions (and some zealotry) around using MS-Excel in statistical analysis, but judged on its merits, it is hard to beat the point-and-click usability of grouping the data from dozens of different perspectives within minutes, specially when you consider the price point.&lt;br /&gt;
&lt;br /&gt;
The pivot tables run out of breath when you are past the point of understanding the data at a macro level and want some form of insight about the data.&lt;br /&gt;
&lt;br /&gt;
Enter &lt;a href=&quot;https://www.ibm.com/watson-analytics&quot; target=&quot;_blank&quot;&gt;Watson Analytics&lt;/a&gt;. In full disclaimer, I just received a professional account from IBM as part of my regular work. A couple of hours exploring the tool proved it was no I-have-to-use-it penalty box, quite the contrary.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Insight in hindsight&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Watson Analytics took only 10 minutes to make me regret the choice of a training feature used in my previous blog entry (&quot;&lt;a data-id=&quot;2040291887085700834&quot; data-item-type=&quot;post&quot; href=&quot;http://sourcepatch.blogspot.com/2018/03/applying-machine-learning-on-study-of.html&quot; itemprop=&quot;url&quot; rel=&quot;bookmark&quot;&gt;Applying machine learning on the study of clinical trial data&lt;/a&gt;&quot;) .&lt;br /&gt;
&lt;br /&gt;
I exported the data to a CSV file and imported it into Watson Analytics. The import gave me a 60% ranking for the quality of the data, which I presume is calculated primarily based on empty fields.&lt;br /&gt;
&lt;br /&gt;
Clicking on the icon for the data set, I was presented with a list of free-formed questions I could choose, none of which involved the target column: overall_status. I then typed&amp;nbsp;&lt;i&gt;&quot;What drives overall_status?&quot;&lt;/i&gt;, hit Enter, and was greeted with the following set of alternatives to explore the answer:&lt;br /&gt;
&lt;br /&gt;
&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-right: 1em; text-align: left;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3T7rJ0HcMizhmAOCyMRX4uK44MYZKVox-veFr3xOJDRe0uTWNMNXg82w4R5i6FNWMlPODjt4C-3LtSr41ea0bc-9lQfwog_sz2hVisfsEJWPu2f65pDz__0KGpzFeXG01I-UzrnTUUbhK/s1600/what.drives.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;551&quot; data-original-width=&quot;1600&quot; height=&quot;220&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3T7rJ0HcMizhmAOCyMRX4uK44MYZKVox-veFr3xOJDRe0uTWNMNXg82w4R5i6FNWMlPODjt4C-3LtSr41ea0bc-9lQfwog_sz2hVisfsEJWPu2f65pDz__0KGpzFeXG01I-UzrnTUUbhK/s640/what.drives.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Free-formed requests for insights&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
I selected the first (and immediate) answer to my question, though I was tempted to follow my nose exploring the others. The next screen presented me with an exhaustive list of the predictive strength of other columns variables for &lt;i&gt;overall_status&lt;/i&gt;, including combinations of two or more columns:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMyjZ2DbNY0lvHng1WDNPWTEZi6bc6kVs7BELtO0IS1ni8QG0KBTCrdqSIYc4oaxD1m4to4uKcgKhbzQ4OanqxCx1njmXcmrE_u1RXvilDFdwNd507y3xtQjupwJoWOwSVPjNLuXPNPhsp/s1600/overall_status.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1074&quot; data-original-width=&quot;1600&quot; height=&quot;427&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMyjZ2DbNY0lvHng1WDNPWTEZi6bc6kVs7BELtO0IS1ni8QG0KBTCrdqSIYc4oaxD1m4to4uKcgKhbzQ4OanqxCx1njmXcmrE_u1RXvilDFdwNd507y3xtQjupwJoWOwSVPjNLuXPNPhsp/s640/overall_status.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Assessment of drivers for a given metric&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
I expected enrollment targets to be a good predictor of overall status, since large centers have more access to patients, solid reputations, as a well as more resources to run the clinical trials. It was intriguing to see &quot;sponsor type&quot; as a co-driver, so I clicked on the &lt;i&gt;&quot;sponsor_type and enrollment&quot;&lt;/i&gt; slot to drill down into it:&lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyBLtcPa83XwSbCXMqCMl5RM_l4kr0cLd0a4VbP0cK-e45pRW1O11PBp_vkw82xrROK7D65fsPvVWum1feRU-bW5HG9UQ1QS3ZcUYEI-x5XLcDa9RVntr71Uz43HAikSqOtmZLXLBEZ8qW/s1600/sponsor.enrollment.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1211&quot; data-original-width=&quot;1600&quot; height=&quot;484&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyBLtcPa83XwSbCXMqCMl5RM_l4kr0cLd0a4VbP0cK-e45pRW1O11PBp_vkw82xrROK7D65fsPvVWum1feRU-bW5HG9UQ1QS3ZcUYEI-x5XLcDa9RVntr71Uz43HAikSqOtmZLXLBEZ8qW/s640/sponsor.enrollment.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Graphical breakdown of relationship amongst different metrics&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
At this point, I am a handful of clicks and one typed question into the experience, and already looking at a new insight (for me) : a disproportionate number of terminated clinical trials had small values (less than 12 ) for the &lt;i&gt;enrollment&lt;/i&gt; column. Going back to my &lt;a href=&quot;https://www.ctti-clinicaltrials.org/aact-database&quot; target=&quot;_blank&quot;&gt;AACT&lt;/a&gt; database instance, I isolated a few clinical trials matching that criteria and read up on their characteristics in &lt;a href=&quot;http://clinicaltrials.gov/&quot;&gt;clinicaltrials.gov&lt;/a&gt;, eventually realizing that there was no way the sponsors for clinical trials with complex eligibility criteria could have possibly set out to have such low number of patients in the studies. Inspecting the &#39;studies&#39; table a little further, I realized that the &lt;i&gt;enrollment&lt;/i&gt; column was further qualified by another column: &lt;i&gt;enrollment_type&lt;/i&gt;. &lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;i&gt;enrollment_type&lt;/i&gt;&amp;nbsp;can be either &#39;&lt;i&gt;Anticipated&lt;/i&gt;&#39; or &#39;&lt;i&gt;Actual&lt;/i&gt;&#39;, with 95% of the clinical trials in my data set having the enrollment type being &#39;&lt;i&gt;Actual&lt;/i&gt;&#39;. Pause for the heart-sinking realization that enrollment data for those clinical trials is updated over time to reflect the number of patients currently enrolled in the clinical trial &lt;i&gt;at the time of its completion or termination&lt;/i&gt;. This finding not only explained the low numbers for many terminated clinical trials, but also meant &lt;i&gt;enrollment&lt;/i&gt;&amp;nbsp;was largely an output field that could not be used to make predictions about the outcome of ongoing trials.&lt;/div&gt;
&lt;br /&gt;
People familiar with clinical trials may be shaking their heads at this point: &lt;i&gt;&quot;of course that is what &#39;enrollment&#39; means&quot;&lt;/i&gt;, though I could also make the case that the number gradually shifts from an output to an input as the clinical trial progresses. In other words, it may still be possible to use it in combination with the elapsed time and phase of a clinical trial, but that deserves a paper of its own.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;b&gt;A new beginning&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Once I eliminated the &lt;i&gt;enrollment&lt;/i&gt; column from the training model, a new run of &lt;a href=&quot;http://sourcepatch.blogspot.com/2018/03/applying-machine-learning-on-study-of.html&quot; target=&quot;_blank&quot;&gt;the predictor&lt;/a&gt; had precision cratered to baseline levels and I was back to square zero. The silver-lining was that the exercise could get restarted on a more solid ground: by analyzing the data before choosing the best features for training a model. &lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
Without the&amp;nbsp;&lt;i&gt;enrollment&lt;/i&gt;&amp;nbsp;column, Watson Analytics showed me this list of predictors:&lt;/div&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga0vUlWfwBIXrddsU14u6Sd3p1_UnflFzDG7AFtjni5Ixtic6DWrIzJwfOFSaEki10stJGORLrauEUGEfYzBI5XMlP3Be61qHMnqa4O7em2N4kjVLw4rJgFn1iqX1shc5CF37isaItxSBz/s1600/driver.no.enrollmnent.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1128&quot; data-original-width=&quot;1600&quot; height=&quot;450&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga0vUlWfwBIXrddsU14u6Sd3p1_UnflFzDG7AFtjni5Ixtic6DWrIzJwfOFSaEki10stJGORLrauEUGEfYzBI5XMlP3Be61qHMnqa4O7em2N4kjVLw4rJgFn1iqX1shc5CF37isaItxSBz/s640/driver.no.enrollmnent.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Drivers after removing &lt;i&gt;enrollment&lt;/i&gt;&amp;nbsp;column&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both;&quot;&gt;
I did not like to see the upper limit of 75% being discouragingly close to the baseline (in the 70%-75% range) , but at this point I did not want to let my newfound set-back with the &lt;i&gt;enrollment&lt;/i&gt; column detract from further exploring the tool.&lt;/div&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
I chose the top pair of drivers (&lt;i&gt;start_epoch&lt;/i&gt; and &lt;i&gt;number_of_facilities&lt;/i&gt;) and Watson Analytics surfaced yet another insight I did not have, annotated with red in the next screenshot:&lt;/div&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2oYH_jePDJwC7xRrNJ9GF-6u0AC5zVNl8DJg0C_LVMmdyTUUuDjANBBGkJXcdF18vMpsLgWnzQqghCn7AiE_isWAscOFLnFmnEcQSpyPWxsBMk3NikLsMgvYDK6ATrNFaQzoyf78JrNx/s1600/prediction.detail.no.enrollment.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1065&quot; data-original-width=&quot;1600&quot; height=&quot;426&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC2oYH_jePDJwC7xRrNJ9GF-6u0AC5zVNl8DJg0C_LVMmdyTUUuDjANBBGkJXcdF18vMpsLgWnzQqghCn7AiE_isWAscOFLnFmnEcQSpyPWxsBMk3NikLsMgvYDK6ATrNFaQzoyf78JrNx/s640/prediction.detail.no.enrollment.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Higher rate of terminations for trials conducted in a single facility&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
The termination rate for trials is noticeably higher for studies involving a single facility. Looking at the next column (2-4 facilities) , the termination rate is a bit lower than for single facilities, but still noticeably higher than the termination rate for trials running in 5 or more facilities. In theory, this can be explained by the fact that the number of facilities correlates with larger organizations. As noted before, these organizations not only have the substantial material resources for planning and conducting the studies across a larger number of locations, they also have more access to patients required for the studies.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;b&gt;A new level of productivity&lt;/b&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
I now have a new batch of notes on choosing features to reboot the earlier exercise in predicting the final status of a clinical trial. It is also clear that exploring the data with a tool that can quickly group the data across multiple dimensions is almost a necessity before developing a machine learning prototype.&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
More than a competent assistant in exploring and finding insights within data, I almost forgot to mention Watson Analytics&#39; flexible visualization mechanism, which stands on its own.&amp;nbsp; With another couple of extra variables added to the previous chart, I had an insightful visualization of agency types, study types, volumes of studies and their final overall status, showing that corporations tend to be more effective in completing studies than other types of sponsors:&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJweuC-cxdPtMqM1L280pLQBjWYjkLPU-B0e8VSsQcd7_OXpjsjREIDjhXRKanAHI0PoNXaRMAkBurthyxWXja5ri0hw7-ZZx3Tbl9Lc7KCaryqC8CAwfgHL4ZkC1WU2hSC8DcoboYxG7P/s1600/bonus.multiple.factors.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;972&quot; data-original-width=&quot;1600&quot; height=&quot;388&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJweuC-cxdPtMqM1L280pLQBjWYjkLPU-B0e8VSsQcd7_OXpjsjREIDjhXRKanAHI0PoNXaRMAkBurthyxWXja5ri0hw7-ZZx3Tbl9Lc7KCaryqC8CAwfgHL4ZkC1WU2hSC8DcoboYxG7P/s640/bonus.multiple.factors.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Flexible composition of new visualization through drag-and-drop of columns&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
I am sure there is more to be explored, but I am already quite impressed with what can be done with the tool within a couple of hours and without external training.</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/8996073070306097486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2018/04/using-watson-analytics-as-part-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/8996073070306097486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/8996073070306097486'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2018/04/using-watson-analytics-as-part-of.html' title='Using Watson Analytics as part of a Machine Learning process'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEQHeNLF8_ySo0Xlqrlmn5EcCQDpNgbQbN2t4g6QBi3S3F7Skfu4Yoqw0l90iZMuEFycxoGXR-FdNYvn10Hya7h_dAgnJO6DUo4ckjo_dh9DXEfR1GPa4Fw5Gtip0fWlIPY4iN0NGC-olM/s72-c/excel.pivot.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3333361346099343040.post-2040291887085700834</id><published>2018-03-25T09:38:00.000-07:00</published><updated>2019-01-03T09:30:03.594-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aact"/><category scheme="http://www.blogger.com/atom/ns#" term="clinical_trials"/><category scheme="http://www.blogger.com/atom/ns#" term="deeplearning"/><category scheme="http://www.blogger.com/atom/ns#" term="tensorflow"/><title type='text'>Applying machine learning to the study of clinical trial data</title><content type='html'>&lt;div class=&quot;wi-article-title article-title-main&quot;&gt;
Documenting my personal side project in studying and visualizing the data about clinical trials.&lt;/div&gt;
&lt;div class=&quot;wi-article-title article-title-main&quot;&gt;
&lt;br /&gt;
&lt;b&gt;Disclaimer&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
In full disclosure, given the time I have for this project, the work is more focused on the technical building blocks than on the disciplined statistical science you will see in papers like &lt;a href=&quot;https://academic.oup.com/biostatistics/advance-article/doi/10.1093/biostatistics/kxx069/4817524&quot; target=&quot;_blank&quot;&gt;&quot;Estimation of clinical trial success rates and related parameters&quot;&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;A technical exercise&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
As the basis for the exercise, I set out to answer a hypothetical question that could be useful for both patients and sponsors of clinical trials: &lt;i&gt;&quot;Will the clinical trial be completed or terminated?&quot;.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Whereas the final overall status of a clinical trial is not necessarily an indication of success or failure for either patient or sponsors, there is certainly some correlation. In terms of technology, I wanted to use&amp;nbsp;&lt;a href=&quot;https://www.tensorflow.org/&quot; target=&quot;_blank&quot;&gt;TensorFlow&lt;/a&gt;&amp;nbsp;to process a subset of structured fields in the clinical trial data to train a machine learning model that can predict the final overall status of the trial.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The data&amp;nbsp;&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
I focused on a training set with interventional trials related to oncology, starting from 2009. I must give another shout out to the  &lt;a href=&quot;https://www.ctti-clinicaltrials.org/&quot; target=&quot;_blank&quot;&gt;Clinical Trials Transformation Initiative&lt;/a&gt; (CTTI) folks for building the &lt;a href=&quot;https://aact.ctti-clinicaltrials.org/&quot; target=&quot;_blank&quot;&gt;AACT database&lt;/a&gt;, which considerably shaved preparation time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxaxro2DuacRTs85zK3U4qG3V9tXoEbEBas7T0DjHj_4ExZuHS4zf9H4IoC_GzWBb_DRQy0InVi1emOBJNeKjhrS7E0ozGbaGTmTcmE7wXRdZ54hAbGoRJcjJqBCng3KLeYM2v_2yK5LMp/s1600/adminer.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;696&quot; data-original-width=&quot;1406&quot; height=&quot;98&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxaxro2DuacRTs85zK3U4qG3V9tXoEbEBas7T0DjHj_4ExZuHS4zf9H4IoC_GzWBb_DRQy0InVi1emOBJNeKjhrS7E0ozGbaGTmTcmE7wXRdZ54hAbGoRJcjJqBCng3KLeYM2v_2yK5LMp/s200/adminer.png&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;With Python and &lt;a href=&quot;https://pandas.pydata.org/&quot; target=&quot;_blank&quot;&gt;Pandas&lt;/a&gt; in tow, I created &lt;a href=&quot;https://github.com/nastacio/clinical-bi/blob/master/src/main/py/ct_data.py&quot; target=&quot;_blank&quot;&gt;the data import module&lt;/a&gt; to query a hosted AACT database on IBM Cloud (See &quot;&lt;a href=&quot;http://sourcepatch.blogspot.com/2018/02/deploying-aggregate-analysis-of.html&quot; target=&quot;_blank&quot;&gt;Deploying the AACT database on a hosted Kubernetes cluster&lt;/a&gt;&quot;). It was equally invaluable to have &lt;a href=&quot;https://www.adminer.org/&quot; target=&quot;_blank&quot;&gt;Adminer&lt;/a&gt; on hand to explore the database contents and prototype some of the SQL statements directly.&lt;br /&gt;
&lt;br /&gt;
With the data source in place, it was time for the&amp;nbsp;&lt;a href=&quot;https://github.com/nastacio/clinical-bi/blob/master/src/main/py/ct_estimator.py#L44&quot; target=&quot;_blank&quot;&gt;second most expensive piece&lt;/a&gt;: converting all the strings in the responses to numbers, bucket columns, identity columns, and embedding columns in TensorFlow.&lt;br /&gt;
&lt;br /&gt;
With all the building blocks in place, it was time to spend countless hours adding and removing features, then running the training and estimation to find out which features worked better than others to increase the accuracy of the prediction.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;(Current) Results&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Given that a high percentage of clinical trials ends up being completed - in the range of 70% to 75% depending on the selection criteria for the trials - there was not a whole lot of room for improvement over the baseline, and&amp;nbsp;at some point the accuracy of this new model maxed out at 81.5% against a baseline of 72.8% for the test set, yielding a gain of 12% over simply guessing &#39;Completed&#39; for all trials.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvnyyuCpnqoFzYTZZrYLyttYhVg4-NiHFXLkn5yk6Giu50xQah9n7aXdpoJ4iCy28mVccUGhqp0qL8_MOKmgcixJ5xDNUlG0BQ_A8QcsBfgyfqRkwfxKMtwknWSMiyrhqNXxNub9KoRukC/s1600/ct.tf.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;255&quot; data-original-width=&quot;1600&quot; height=&quot;102&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvnyyuCpnqoFzYTZZrYLyttYhVg4-NiHFXLkn5yk6Giu50xQah9n7aXdpoJ4iCy28mVccUGhqp0qL8_MOKmgcixJ5xDNUlG0BQ_A8QcsBfgyfqRkwfxKMtwknWSMiyrhqNXxNub9KoRukC/s640/ct.tf.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
To recreate the results, if you have docker installed and running, simply execute this command from a terminal:&lt;br /&gt;
&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;


&lt;br /&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span class=&quot;s1&quot;&gt;&lt;span style=&quot;color: #f1c232; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: xx-small;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span class=&quot;s1&quot;&gt;&lt;span style=&quot;color: #f1c232; font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: xx-small;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: black;&quot;&gt;docker run --rm -it dnastacio/tensorflow-ct&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;/div&gt;
After a couple of minutes of data loading and training, you should see the accuracy for the trained model and the prediction for a few examples on the screen.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmD0rY8n3hoZrkXr2MS0xr926J5Wk6tY_ze16lmjnPRx591Hufy5-KNsdsB-bPyTAEXn_RabTZUna68SPNyjDcRq8oj4E1YkhNKtAsqg3B7MVcxgKKUB0y9lYVk2flAogHpVUJHwzsZNm4/s1600/ct.preds.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;570&quot; data-original-width=&quot;1106&quot; height=&quot;205&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmD0rY8n3hoZrkXr2MS0xr926J5Wk6tY_ze16lmjnPRx591Hufy5-KNsdsB-bPyTAEXn_RabTZUna68SPNyjDcRq8oj4E1YkhNKtAsqg3B7MVcxgKKUB0y9lYVk2flAogHpVUJHwzsZNm4/s400/ct.preds.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Note that I am still using random slices of the data set on each run to avoid optimizing the model for a given slice, so results will vary across runs. I still need to go back and pick a set of clinical trials as a fixed ground truth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conclusion and next steps&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Though early results are not a major gain over the baseline, that is expected at this stage of development. This is still largely a exercise to assess and integrate building blocks into a solution for this kind of problem, such as transforming data from relational databases into usable tensors inside TensorFlow. I still want to go through a few more exercise steps: (1) building a deep-wide model to separate dense from sparse features in the current set and (2) using word2vec on the contents of clinical trial description and eligibility criteria.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Beyond the technology, I have also invested time reading articles on the causes of clinical trial termination and talking to experts in the field, which points at promising additions to the model. Unfortunately, some of these features are not well-populated in the clinical trials database, so that their inclusion will require concerted and localized work to clean up the data series for each feature.&lt;br /&gt;
&lt;br /&gt;
One simple example of such a feature is the allocation strategy for the clinical trial (randomized vs. non-randomized allocation across different arms) . Despite consensus from experts about randomized allocation being a big factor in the patient&#39;s decision to join or leave a clinical trial, there was no gain in accuracy of prediction after adding that field to the model. I then charted the distribution of the input values in the database, just to find out that it is empty on the majority of clinical trials. Cleaning up that one data series can easily become a machine learning project of its own.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmy7Zf7s8a16Ik92QBwY43jFkZ_KsDPxK6bNOLZpYoUyCzDiqlBlI0pYFPmCgXHiywfE75VCh1930906Vy6_FQ5ZZCksOui7rb5Ho3ESv0VIBvUpIDPzEvOhfdVegd3kg-HZaKEJ7_b5u0/s1600/ct.allocation.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;494&quot; data-original-width=&quot;916&quot; height=&quot;172&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmy7Zf7s8a16Ik92QBwY43jFkZ_KsDPxK6bNOLZpYoUyCzDiqlBlI0pYFPmCgXHiywfE75VCh1930906Vy6_FQ5ZZCksOui7rb5Ho3ESv0VIBvUpIDPzEvOhfdVegd3kg-HZaKEJ7_b5u0/s320/ct.allocation.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Helvetica Neue&#39;; color: #454545}
&lt;/style&gt;&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &#39;Andale Mono&#39;; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
&lt;/style&gt;</content><link rel='replies' type='application/atom+xml' href='http://sourcepatch.blogspot.com/feeds/2040291887085700834/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://sourcepatch.blogspot.com/2018/03/applying-machine-learning-on-study-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2040291887085700834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3333361346099343040/posts/default/2040291887085700834'/><link rel='alternate' type='text/html' href='http://sourcepatch.blogspot.com/2018/03/applying-machine-learning-on-study-of.html' title='Applying machine learning to the study of clinical trial data'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxaxro2DuacRTs85zK3U4qG3V9tXoEbEBas7T0DjHj_4ExZuHS4zf9H4IoC_GzWBb_DRQy0InVi1emOBJNeKjhrS7E0ozGbaGTmTcmE7wXRdZ54hAbGoRJcjJqBCng3KLeYM2v_2yK5LMp/s72-c/adminer.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>