<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter Wong</title>
    <description>The latest articles on DEV Community by Peter Wong (@peterwong).</description>
    <link>https://dev.to/peterwong</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F916782%2Fe978e3bf-1874-4424-936c-04e1572b8fce.jpg</url>
      <title>DEV Community: Peter Wong</title>
      <link>https://dev.to/peterwong</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/peterwong"/>
    <language>en</language>
    <item>
      <title>Reducing Lead Time for Changes</title>
      <dc:creator>Peter Wong</dc:creator>
      <pubDate>Mon, 03 Oct 2022 05:39:01 +0000</pubDate>
      <link>https://dev.to/aws-builders/reducing-lead-time-for-change-2b07</link>
      <guid>https://dev.to/aws-builders/reducing-lead-time-for-change-2b07</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxtnfvx9owv1et205q7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgxtnfvx9owv1et205q7u.png" alt="Lead Time vs Cycle Time vs Lead Time for Changes" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our previous &lt;a href="https://dev.to/aws-builders/dynamic-kubernetes-based-feature-environment-on-aws-2cn6"&gt;post&lt;/a&gt; describes how we have implemented a &lt;strong&gt;Dynamic Feature Environment&lt;/strong&gt; that would allow engineers at Prenetics to spin up/down a fully functional independent K8s cluster that runs our full set of microservices, offering an internal &lt;strong&gt;Environment as a Service (EaaS)&lt;/strong&gt;. The aim is to provide the necessary tools for our engineers to easily build and test &lt;strong&gt;locally&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://prenetics.com/" rel="noopener noreferrer"&gt;Prenetics&lt;/a&gt; Engineering we also look at improving our delivery efficiency. &lt;strong&gt;Lead Time for Changes (LT)&lt;/strong&gt; is a one of the four &lt;a href="https://cloud.google.com/blog/products/devops-sre/using-the-four-keys-to-measure-your-devops-performance" rel="noopener noreferrer"&gt;DORA metrics&lt;/a&gt; and it measures the amount of time a commit would take to get into production. Reducing LT would mean faster Time to market.&lt;/p&gt;

&lt;p&gt;We split our LT improvements into the following phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Provision&lt;/li&gt;
&lt;li&gt;Build&lt;/li&gt;
&lt;li&gt;Deploy&lt;/li&gt;
&lt;li&gt;Test&lt;/li&gt;
&lt;li&gt;Release&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the following we look at how we have been optimising the &lt;strong&gt;provision&lt;/strong&gt; phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provision
&lt;/h2&gt;

&lt;p&gt;We use CodeBuild to execute build and test steps, and to deploy our digital assets&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;k8s changes via &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS Cli&lt;/a&gt; and &lt;a href="https://kubernetes.io/docs/reference/kubectl/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;web changes via AWS Cli to S3&lt;/li&gt;
&lt;li&gt;mobile changes via &lt;a href="https://expo.dev/" rel="noopener noreferrer"&gt;Expo Cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;infrastructure changes via &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of our CodeBuild projects executes the required steps inside its specified Docker container. AWS offers a number of &lt;a href="https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html" rel="noopener noreferrer"&gt;standard Docker images&lt;/a&gt;. However, these images do not have a number of applications needed in our build, deploy and test steps. We have therefore defined our own CodeBuild Docker image (see &lt;a href="https://gist.github.com/peteryhwong/7bbbe461b028f5040c81cdcea2f256af" rel="noopener noreferrer"&gt;https://gist.github.com/peteryhwong/7bbbe461b028f5040c81cdcea2f256af&lt;/a&gt; is a snippet of the &lt;code&gt;Dockerfile&lt;/code&gt;), Our custom Docker image defines from an Linux Alpine based "Docker in Docker" image and pre-installed the tools such as &lt;code&gt;jq&lt;/code&gt;, &lt;code&gt;terraform&lt;/code&gt;, &lt;code&gt;kubectl&lt;/code&gt;, and &lt;code&gt;AWS Cli&lt;/code&gt; that are needed in our build, deploy and test steps. This custom image is &lt;strong&gt;smaller&lt;/strong&gt; in size and it means our steps do not need to download the same external dependencies in &lt;strong&gt;every execution&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This image is stored in our &lt;a href="https://aws.amazon.com/ecr/" rel="noopener noreferrer"&gt;AWS ECR&lt;/a&gt; and is provisioned when CodeBuild projects execute.&lt;/p&gt;

&lt;p&gt;Note that unlike the AWS standard images, containers created from our custom image would not the Docker daemon (&lt;code&gt;dockerd&lt;/code&gt;) running by default, hence we would need to start Docker daemon manually when the container starts. See &lt;a href="https://gist.github.com/peteryhwong/a51c39d69647c233808339c62d7b8f28" rel="noopener noreferrer"&gt;https://gist.github.com/peteryhwong/a51c39d69647c233808339c62d7b8f28&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;On average we see a reduction of up to a minute during the provision phase of our CodeBuild projects and our typical microservice's build phase is normally less than 5 minutes.&lt;/p&gt;

&lt;p&gt;In our next post we will look at how we have been optimising the &lt;strong&gt;build&lt;/strong&gt; phase.&lt;/p&gt;

</description>
      <category>dora</category>
      <category>cicd</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>Dynamic Kubernetes based Feature Environment on AWS</title>
      <dc:creator>Peter Wong</dc:creator>
      <pubDate>Mon, 12 Sep 2022 17:14:02 +0000</pubDate>
      <link>https://dev.to/aws-builders/dynamic-kubernetes-based-feature-environment-on-aws-2cn6</link>
      <guid>https://dev.to/aws-builders/dynamic-kubernetes-based-feature-environment-on-aws-2cn6</guid>
      <description>&lt;p&gt;At &lt;a href="https://www.prenetics.com" rel="noopener noreferrer"&gt;Prenetics&lt;/a&gt;, our mission is to decentralise healthcare by offering affordable and accessible healthcare services across the pillars of Prevention, Diagnostic and Personalised Care to the public. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Prenetics/engineering" rel="noopener noreferrer"&gt;Engineering at Prenetics&lt;/a&gt; focuses on delivering robust, secure and scalable capabilities to our digital products and services. We deploy our API as microservices onto K8s (&lt;a href="https://aws.amazon.com/eks/" rel="noopener noreferrer"&gt;AWS EKS&lt;/a&gt;) and have implemented an &lt;a href="https://ncarb.github.io/eks-workshop/intermediate/230_logging/" rel="noopener noreferrer"&gt;EFK&lt;/a&gt; stack for centralised logging, monitoring and alerting. We have implemented CI/CD pipelines using &lt;a href="https://aws.amazon.com/codepipeline/" rel="noopener noreferrer"&gt;CodePipeline&lt;/a&gt; and have been practicing &lt;a href="https://en.wikipedia.org/wiki/Continuous_delivery" rel="noopener noreferrer"&gt;Continuous Delivery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our core engineering principle is "You build it; you run it" and in order for our engineers to fully embrace this DevOps model, they must be able to easily build and test &lt;strong&gt;locally&lt;/strong&gt;, thereby reducing the build and test feedback loop to the minimum. To this end we have developed the Dynamic Feature Environment. &lt;/p&gt;

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

&lt;p&gt;Dynamic Feature Environment allows engineers to spin up/down a &lt;strong&gt;fully functional independent K8s cluster that runs our full set of microservices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Precisely, a dynamic feature environment consists of an EC2 instance running &lt;a href="https://minikube.sigs.k8s.io/docs/" rel="noopener noreferrer"&gt;Minikube&lt;/a&gt; and connecting to a small &lt;a href="https://aws.amazon.com/rds/" rel="noopener noreferrer"&gt;RDS&lt;/a&gt; instance that is created from a snapshot of our integration environment's RDS.&lt;/p&gt;

&lt;p&gt;There are two &lt;a href="https://aws.amazon.com/image-builder/" rel="noopener noreferrer"&gt;EC2 Image Builder&lt;/a&gt; pipelines. The &lt;code&gt;Minikube Ingress&lt;/code&gt; pipeline creates a AMI based on an Amazon Linux 2 base image. The pipeline installs Minikube, enables its ingress (&lt;code&gt;minikube addons enable ingress&lt;/code&gt;), and also installs tools needed to deploy our microservices. The &lt;code&gt;Minikube Service&lt;/code&gt; pipeline creates a AMI based on the output of &lt;code&gt;Minikube Ingress&lt;/code&gt; and caches the latest Docker images (from AWS &lt;a href="https://aws.amazon.com/ecr/" rel="noopener noreferrer"&gt;ECR&lt;/a&gt;) of our microservices. This pipeline is triggered daily.&lt;/p&gt;

&lt;p&gt;There is a &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;Lambda function&lt;/a&gt; (&lt;code&gt;lambda-devlauncher&lt;/code&gt;) that our engineers can invoke to spin up an &lt;a href="https://aws.amazon.com/ec2/" rel="noopener noreferrer"&gt;EC2&lt;/a&gt; instance using the latest AMI from &lt;code&gt;Minikube Service&lt;/code&gt;. This EC2 instance sits on the public subnet (with a public IP address) and is only accessible within our internal network (VPN). The EC2 instance's user data fetches the latest Docker images (from AWS ECR) of our microservices as well as the images of the &lt;strong&gt;services under test&lt;/strong&gt;. The user data exposes the APIs, the cluster's K8s dashboard (&lt;code&gt;minikube dashboard&lt;/code&gt;), and a centralised logviewer (&lt;code&gt;minikube addons enable logviewer&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The Lambda function also creates a small RDS instance to be used by the feature environment. It is created from the latest snapshot of our integration environment's RDS. In practice we always have &lt;code&gt;n+1&lt;/code&gt; small RDS instances, where &lt;code&gt;n&lt;/code&gt; is the number of feature environments running, so the time needed to spin up a dynamic feature environment is reduced to the minimum. &lt;/p&gt;

&lt;p&gt;There is an &lt;a href="https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is.html" rel="noopener noreferrer"&gt;EventBridge&lt;/a&gt; rule that invokes the lambda function daily to terminate any old feature environments and to create 1 small RDS instance for usage.&lt;/p&gt;

&lt;p&gt;The time from invoking the lambda function to having the environment ready is around 12 minutes.&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>kubernetes</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
