<?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>Forem: Ash Wu</title>
    <description>The latest articles on Forem by Ash Wu (@hsatac).</description>
    <link>https://forem.com/hsatac</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%2F46147%2F0c12243c-4fed-443a-9ee7-8c229ceb20a2.jpg</url>
      <title>Forem: Ash Wu</title>
      <link>https://forem.com/hsatac</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hsatac"/>
    <language>en</language>
    <item>
      <title>Use non-root user in scratch docker image</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Fri, 07 Jun 2024 02:00:05 +0000</pubDate>
      <link>https://forem.com/hsatac/use-non-root-user-in-scratch-docker-image-1c0o</link>
      <guid>https://forem.com/hsatac/use-non-root-user-in-scratch-docker-image-1c0o</guid>
      <description>&lt;p&gt;It's considered best practice to use non-root user in docker images, even if it's built from scratch image.&lt;/p&gt;

&lt;p&gt;But in scratch image it's really empty, you can't use commands like useradd to create a non-root user.&lt;/p&gt;

&lt;p&gt;We can use &lt;a href="https://medium.com/@lizrice/non-privileged-containers-based-on-the-scratch-image-a80105d6d341"&gt;multi stage builders&lt;/a&gt; to achieve this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ubuntu:latest
RUN useradd -u 10001 scratchuser
FROM scratch
COPY dosomething /dosomething
COPY --from=0 /etc/passwd /etc/passwd
USER scratchuser
ENTRYPOINT ["/dosomething"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How can we verify it? In order to verify, we need &lt;code&gt;id&lt;/code&gt; command to check if the user is set correctly. We can copy the commands from &lt;code&gt;busybox&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM busybox:1.35.0-uclibc as busybox

COPY --from=busybox /bin/sh /bin/sh
COPY --from=busybox /bin/id /bin/id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we can use &lt;code&gt;docker exec&lt;/code&gt; to run the &lt;code&gt;id&lt;/code&gt; command to verify if it works.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>security</category>
    </item>
    <item>
      <title>Kamal Deploy on GCP</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Sat, 17 Feb 2024 04:48:56 +0000</pubDate>
      <link>https://forem.com/hsatac/kamal-deploy-on-gcp-18jn</link>
      <guid>https://forem.com/hsatac/kamal-deploy-on-gcp-18jn</guid>
      <description>&lt;p&gt;Kamal (&lt;a href="https://kamal-deploy.org/"&gt;https://kamal-deploy.org/&lt;/a&gt;) serves as the Docker equivalent of Capistrano, presenting a familiar interface to those already acquainted with Capistrano.&lt;/p&gt;

&lt;p&gt;In this article, I'll share insights gained from deploying a web application on Google Cloud Platform (GCP) using Kamal. Rather than offering a one-size-fits-all guide, I aim to provide a collection of useful snippets and references to facilitate your project's deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilizing GCP's Artifact Registry
&lt;/h2&gt;

&lt;p&gt;The integration of Kamal with GCP's Artifact Registry is streamlined by an ongoing PR (&lt;a href="https://github.com/basecamp/kamal-site/pull/35"&gt;https://github.com/basecamp/kamal-site/pull/35&lt;/a&gt;). For seamless operation, configure the following in your Kamal settings, ensuring to replace the placeholders with your specific project details and incorporating the service account's JSON key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your gcp project id&amp;gt;/&amp;lt;artifact registry repo name&amp;gt;/&amp;lt;desired image name&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your registry region&amp;gt;-docker.pkg.dev&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;_json_key_base64&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;KAMAL_REGISTRY_PASSWORD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Secure SSH Access via IAP
&lt;/h2&gt;

&lt;p&gt;To securely SSH into GCP's Compute Engine VMs, the use of Identity-Aware Proxy (IAP) is advocated. Before proceeding, verify your ability to SSH via IAP by following GCP's official guide (&lt;a href="https://cloud.google.com/compute/docs/connect/ssh-using-iap"&gt;https://cloud.google.com/compute/docs/connect/ssh-using-iap&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In the Kamal configuration file, define your server host as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;myhost.us-west1-a.my-gcp-project"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting up Proxy Command
&lt;/h3&gt;

&lt;p&gt;For a smooth SSH connection, download and implement this script (&lt;a href="https://gist.github.com/hSATAC/d72bd174f8845d8b9995f8921fe13b39"&gt;https://gist.github.com/hSATAC/d72bd174f8845d8b9995f8921fe13b39&lt;/a&gt;) as your proxy_command. This script, compatible with both macOS and Linux, facilitates usage across various environments including CI runners.&lt;/p&gt;

&lt;p&gt;Locate the script within the project at &lt;code&gt;./.kamal/scripts/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;ssh&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;proxy_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sh ./.kamal/scripts/gcp-start-iap-tunnel-ssh-proxy-magic.sh gce_instance=%h sshuser=root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enabling Root SSH Access
&lt;/h3&gt;

&lt;p&gt;Though Kamal permits SSH access under any username, employing the root user simplifies processes, adhering to Kamal's default assumptions.&lt;/p&gt;

&lt;p&gt;Enable root SSH access as per GCP's guidance (&lt;a href="https://cloud.google.com/compute/docs/connect/root-ssh#gcloud"&gt;https://cloud.google.com/compute/docs/connect/root-ssh#gcloud&lt;/a&gt;), and in your SSH configuration (&lt;code&gt;~/.ssh/config&lt;/code&gt;), include a reference to Google's Compute Engine private key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;Host *.my-gcp-project&lt;/span&gt;
  &lt;span class="s"&gt;IdentityFile ~/.ssh/google_compute_engine&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kamal</category>
      <category>gcp</category>
      <category>devops</category>
    </item>
    <item>
      <title>HowTo: Find egress traffic destination in Istio service mesh</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Fri, 18 Nov 2022 05:53:28 +0000</pubDate>
      <link>https://forem.com/hsatac/howto-find-egress-traffic-destination-in-istio-service-mesh-4l61</link>
      <guid>https://forem.com/hsatac/howto-find-egress-traffic-destination-in-istio-service-mesh-4l61</guid>
      <description>&lt;p&gt;Before we enable the &lt;code&gt;REGISTRY_ONLY&lt;/code&gt; options for Istio, we want to capture all the existing outbound traffic and add it as a ServiceEntry.&lt;/p&gt;

&lt;p&gt;There are two metrics we can monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;istio_requests_total{destination_service_name="PassthroughCluster"}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;istio_tcp_connections_closed_total{destination_service_name="PassthroughCluster"}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can query these two metrics in prometheus to see if there’s any outbound traffic that was not registered yet.&lt;/p&gt;

&lt;p&gt;The first one &lt;code&gt;istio_requests_total&lt;/code&gt; is easy. It captures all the http requests. And because it’s a http request, the domain will be recorded in the &lt;code&gt;destination_service&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;The second one &lt;code&gt;istio_tcp_connections_closed_total&lt;/code&gt; is more complicated. It may be an HTTPS or TCP request. And for these requests the destination domain was not recorded. The only thing we can know is which workload generated these requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Envoy Debug Log
&lt;/h2&gt;

&lt;p&gt;To find out where the request is going, we must first turn on the debug log of the sidecar proxy. There are two ways we can do that.&lt;/p&gt;

&lt;p&gt;The first one is to add an annotation to the workload: &lt;code&gt;sidecar.istio.io/logLevel: debug&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you don’t want to restart the pod, you can also use istioctl to enable debug log during runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;istioctl pc log &amp;lt;pod_name&amp;gt;.&amp;lt;namespace&amp;gt; &lt;span class="nt"&gt;--level&lt;/span&gt; debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the debug log was enabled, we then needed to trigger the application to make it send those requests. And then we can try to find &lt;code&gt;PassthroughCluster&lt;/code&gt; in the logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k logs &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; &amp;lt;pod_name&amp;gt; &lt;span class="nt"&gt;-c&lt;/span&gt; istio-proxy | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Creating connection to cluster PassthroughCluster"&lt;/span&gt; &lt;span class="nt"&gt;-B2&lt;/span&gt; &lt;span class="nt"&gt;-A2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you enabled the &lt;code&gt;REGISTRY_ONLY&lt;/code&gt; mode of the Istio service mesh, there will be no &lt;code&gt;PassthroughCluster&lt;/code&gt;, instead, you should be monitoring &lt;code&gt;BlackholeCluster&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Envoy Access Log
&lt;/h2&gt;

&lt;p&gt;Another tool we can use is the access log of envoy proxy. We can enable the access log for specified namespace and workload. Here’s an example of enabling envoy access log for monitoring namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;telemetry.istio.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Telemetry&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;envoy-access-log&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;monitoring&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;accessLogging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;envoy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we can tail the log and pipe to &lt;a href="https://github.com/nitishm/engarde"&gt;engarde&lt;/a&gt; to view the logs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k logs &lt;span class="nt"&gt;-n&lt;/span&gt; &amp;lt;namespace&amp;gt; &amp;lt;pod_name&amp;gt; &lt;span class="nt"&gt;-c&lt;/span&gt; istio-proxy &lt;span class="nt"&gt;-f&lt;/span&gt; | engarde &lt;span class="nt"&gt;--use-istio&lt;/span&gt; | jq &lt;span class="s1"&gt;'select(.upstream_cluster=="BlackHoleCluster")'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kubernetes</category>
      <category>istio</category>
      <category>servicemesh</category>
      <category>envoy</category>
    </item>
    <item>
      <title>Write a PHP library supports PHP 5.6 to 8.1</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Mon, 24 Oct 2022 04:02:18 +0000</pubDate>
      <link>https://forem.com/hsatac/write-a-php-library-supports-php-56-to-81-48fe</link>
      <guid>https://forem.com/hsatac/write-a-php-library-supports-php-56-to-81-48fe</guid>
      <description>&lt;p&gt;Yes, you heard it right. We need to write a PHP library that supports from PHP 5.6 to PHP 8.1&lt;/p&gt;

&lt;p&gt;There are still people out there using EOL PHP versions and we still want them to be able use our package.&lt;/p&gt;

&lt;p&gt;Things that needs to be done needs to be done. Let's get to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;Actually writing the code itself is probably the easiest part. You just don't use the fancy new stuff and stick to the old way.&lt;/p&gt;

&lt;p&gt;I run two tools for this - &lt;a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer"&gt;php-cs-fixer&lt;/a&gt; on PHP 5.6 and the built-in syntax checker(&lt;code&gt;php -l&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;There's an existing Github Action &lt;a href="https://github.com/PrestaShopCorp/github-action-php-lint"&gt;prestashop/github-action-php-lint&lt;/a&gt; which handles this for you.&lt;/p&gt;

&lt;p&gt;A full example of these two checks can be found &lt;a href="https://github.com/smartpay-co/sdk-php/blob/master/.github/workflows/php.yml"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tests
&lt;/h2&gt;

&lt;p&gt;Writing the code is easy, but writing the tests is not. PHPUnit &lt;a href="https://phpunit.de/supported-versions.html"&gt;does not support old PHP versions&lt;/a&gt; and you can't use the latest PHP version with old PHPUnit version due to syntax issues.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Yoast/PHPUnit-Polyfills"&gt;Yaost/PHPUnit-Polyfills&lt;/a&gt; came to rescue. With just tiny adjustments to your tests, this can make your tests run across PHPUnit 4.8~9.x and PHP 5.4+&lt;/p&gt;

&lt;h2&gt;
  
  
  The CI
&lt;/h2&gt;

&lt;p&gt;We also want to run tests for different versions automatically so we don't have to manually tests everything.&lt;/p&gt;

&lt;p&gt;The official PHPUnit &amp;amp; composer Github Action didn't play well with old PHP versions.&lt;/p&gt;

&lt;p&gt;I found &lt;a href="https://github.com/shivammathur/setup-php"&gt;shivammathur/setup-php&lt;/a&gt; did a better job on supporting old PHP versions, and you don't have to worry about the composer &amp;amp; extension compatibility, it handles those for you.&lt;/p&gt;

&lt;p&gt;Here's a &lt;a href="https://github.com/smartpay-co/sdk-php/blob/master/.github/workflows/pr.yml"&gt;full example&lt;/a&gt; that you can run a matrix of PHP versions for your tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Writing a PHP library that supports from PHP 5.6 to PHP 8.1 is not as hard as I imagine at the very beginning. PHP handles backward-compatibility very well. PHPUnit took me most of the time to figure out. Hopefully there're already a tool for that. I am not alone.&lt;/p&gt;

&lt;p&gt;Hope this helps someone out there, trying to do the same thing.&lt;/p&gt;

</description>
      <category>php</category>
      <category>phpunit</category>
    </item>
    <item>
      <title>Building A Ubuntu VirtualBox Image on AWS EC2 With Packer</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Fri, 16 Apr 2021 02:38:30 +0000</pubDate>
      <link>https://forem.com/hsatac/building-a-ubuntu-virtualbox-image-on-aws-ec2-with-packer-m00</link>
      <guid>https://forem.com/hsatac/building-a-ubuntu-virtualbox-image-on-aws-ec2-with-packer-m00</guid>
      <description>&lt;p&gt;Building a virtualbox image on AWS EC2 with packer - this sounds straightforward, how hard could it be?&lt;/p&gt;

&lt;p&gt;Indeed, it's relatively simple because there are existing tools and tutorials our there, but I still ran into a few hiccups during my experiment and I think it's worth nothing that down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;Some background first. I need to build a VirtualBox image as a part of the release. There are few different approaches. In the past I did this with Vagrant and VirtualBox in my home-made Jenkins CI. So naturally I would dig in this way.&lt;/p&gt;

&lt;p&gt;But now we're using CircleCI and it's hard to get VirtualBox running inside CircleCI environment.&lt;/p&gt;

&lt;p&gt;I also checked AWS, AWS doesn't support nested virtualization unless you're using an expensive bare-metal machine. GCP supports &lt;a href="https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances"&gt;nested virtualization&lt;/a&gt; but at that point I decided not to mess with it.&lt;/p&gt;

&lt;p&gt;Chances are that we may need to build a AWS AMI too in the future, so after some digging I decide to use &lt;a href="https://www.packer.io/"&gt;Packer&lt;/a&gt; with its &lt;a href="https://www.packer.io/docs/builders/amazon/ebs"&gt;amazon-ebs&lt;/a&gt; builder to build an AMI and then utilize aws-cli to &lt;a href="https://docs.aws.amazon.com/vm-import/latest/userguide/vmexport_image.html"&gt;export AMI to VMDK&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packer
&lt;/h2&gt;

&lt;p&gt;Using Packer to build an AMI is quite easy. Here's an example hcl file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"ami_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${env("&lt;/span&gt;&lt;span class="nx"&gt;CUSTOM_AMI_NAME&lt;/span&gt;&lt;span class="s2"&gt;")}"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ap-northeast-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"amazon-ebs"&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami_name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.ami_name}"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"c4.2xlarge"&lt;/span&gt;
  &lt;span class="nx"&gt;ssh_pty&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.region}"&lt;/span&gt;
  &lt;span class="nx"&gt;source_ami_filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;filters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu/images/*ubuntu-bionic-18.04-amd64-server-*"&lt;/span&gt;
      &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;device&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ebs"&lt;/span&gt;
      &lt;span class="nx"&gt;virtualization&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hvm"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;most_recent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;owners&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"099720109477"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;launch_block_device_mappings&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;device_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/dev/sda1"&lt;/span&gt;
    &lt;span class="nx"&gt;volume_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;
    &lt;span class="nx"&gt;volume_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"gp2"&lt;/span&gt;
    &lt;span class="nx"&gt;delete_on_termination&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;ssh_username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;sources&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"source.amazon-ebs.ubuntu"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;provisioner&lt;/span&gt; &lt;span class="s2"&gt;"shell"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"./server_setup.sh"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are few things we need to pay attention here in the bootstrap script.&lt;/p&gt;

&lt;p&gt;First, you'll want to wait until cloud-init is finished to proceed your script. Otherwise there will be random failures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Wait for cloud-init to finish&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /var/lib/cloud/instance/boot-finished &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Waiting for cloud-init...'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Second, if you build the AMI and export to VMDK, import it in your VirtualBox now, you'll find that there's no network interface in your virtual machine. Because those AMIs on AWS are optimized for cloud environments, we need to tweak a little bit after your bootstrap is finished.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Remove cloud-init to speed up the boot in virtualbox&lt;/span&gt;
&lt;span class="nb"&gt;sudo touch&lt;/span&gt; /etc/cloud/cloud-init.disabled
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt remove cloud-init &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /etc/cloud/&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/cloud/

&lt;span class="c"&gt;# Setup network in virtualbox&lt;/span&gt;
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; /etc/netplan/50-cloud-init.yaml
&lt;span class="nb"&gt;sudo &lt;/span&gt;bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"cat &amp;gt; /etc/netplan/config.yaml"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
network:
  version: 2
  renderer: networkd
  ethernets:
    id0:
      match:
        name: en*
      dhcp4: yes
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"echo '@reboot /usr/sbin/netplan apply' | crontab -"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you can convert AMI to VMDK on S3 when packer finished the building process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CUSTOM_AMI_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-ami-name
packer build example.pkr.hcl

&lt;span class="nv"&gt;AMI_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws ec2 describe-images &lt;span class="nt"&gt;--owners&lt;/span&gt; self &lt;span class="nt"&gt;--filters&lt;/span&gt; &lt;span class="s2"&gt;"Name=name,Values=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CUSTOM_AMI_NAME&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;ImageId | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-f4&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

aws ec2 export-image &lt;span class="nt"&gt;--image-id&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;AMI_ID&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;--disk-image-format&lt;/span&gt; VMDK &lt;span class="nt"&gt;--s3-export-location&lt;/span&gt; &lt;span class="nv"&gt;S3Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bucketname,S3Prefix&lt;span class="o"&gt;=&lt;/span&gt;prefixname/

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

&lt;/div&gt;



</description>
      <category>aws</category>
      <category>ec2</category>
      <category>virtualbox</category>
      <category>packer</category>
    </item>
    <item>
      <title>My IME setup for Windows 10</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Tue, 31 Dec 2019 01:10:28 +0000</pubDate>
      <link>https://forem.com/hsatac/my-ime-setup-for-windows-10-h3l</link>
      <guid>https://forem.com/hsatac/my-ime-setup-for-windows-10-h3l</guid>
      <description>&lt;p&gt;It has been a huge pain for me to type Chinese in Windows 10. And it was the main reason I dislike Windows 10.&lt;/p&gt;

&lt;p&gt;The problem is that I am used to switch between English &amp;amp; Chinese input methods by typing &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt;. This went way back from Windows 95, or even Windows 3.1&lt;/p&gt;

&lt;p&gt;But suddenly it changed in Windows 10. You'll have to use &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; to switch between input methods, and &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt; became disable/enable the method.&lt;/p&gt;

&lt;p&gt;What I'd like to have is the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;English as the default input methods, no matter which window I go.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt; to switch between English &amp;amp; Chinese input methods.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the default Windows 10 setting, I could only get one of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Default English, use &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Shift&lt;/code&gt; to switch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Default Chinese, use &lt;code&gt;Shift&lt;/code&gt; or &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt; to switch to English&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these satisfied me and I don't really want to adopt myself to get use to it.&lt;/p&gt;

&lt;p&gt;I used lots of workarounds before, but today I believe I found the perfect solution: &lt;a href="https://autohotkey.com"&gt;autohotkey&lt;/a&gt; + regedit.&lt;/p&gt;

&lt;p&gt;For autohotkey, I have these two settings in a &lt;code&gt;ime.ahk&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;^Space::#Space
CapsLock::Ctrl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And put this into startup folder so it could be loaded on boot.&lt;/p&gt;

&lt;p&gt;But this script sometimes failed, and my IME will be disabled. I'll have to suspend the autohotkey script and restore it, turn the script back up.&lt;/p&gt;

&lt;p&gt;So here comes the second fix: disable the original &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;Space&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Follow the &lt;a href="https://superuser.com/questions/327479/ctrl-space-always-toggles-chinese-ime-windows-7"&gt;instruction&lt;/a&gt; here, use &lt;code&gt;regedit&lt;/code&gt; and disable this keybinding.&lt;/p&gt;

&lt;p&gt;Finally I can type normally in Chinese on Windows 10. &lt;/p&gt;

</description>
      <category>win10</category>
      <category>ime</category>
    </item>
    <item>
      <title>Management GUI for Elasticsearch</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Tue, 18 Dec 2018 09:58:06 +0000</pubDate>
      <link>https://forem.com/hsatac/management-gui-for-elasticsearch-17g9</link>
      <guid>https://forem.com/hsatac/management-gui-for-elasticsearch-17g9</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;Elasticsearch is a developer-friendly, with minimal configuration &amp;amp; manual management. But sometimes we still want to know more about our cluster.&lt;/p&gt;

&lt;p&gt;You can fetch these information from elasticsearch APIs, so if you're a elasticsearch API ninja you can skip this article.&lt;/p&gt;

&lt;p&gt;Here are some tools that I prefer, to help me to quickly get the overview of the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite
&lt;/h2&gt;

&lt;p&gt;Usually our cluster is located in private VPC, so we have to port-forward to our local machine.&lt;/p&gt;

&lt;p&gt;What I usually do is to forward the kubernetes API to my local machine, and use &lt;code&gt;kubectl port-forward&lt;/code&gt; to handle the rest.&lt;/p&gt;

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

    &lt;span class="c"&gt;# I modified the kubeconfig to use port 16443 for remote environments&lt;/span&gt;
    &lt;span class="nv"&gt;$ &lt;/span&gt;ssh &lt;span class="nt"&gt;-L&lt;/span&gt; 16443:127.0.0.1:6443 ssh-jumper

    &lt;span class="c"&gt;# port-foward elasticsearch to localhost&lt;/span&gt;
    &lt;span class="nv"&gt;$ &lt;/span&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; logging port-forward elasticsearch-data-0 9200:9200

    &lt;span class="c"&gt;# check if it's ready&lt;/span&gt;
    &lt;span class="nv"&gt;$ &lt;/span&gt;curl localhost:9200


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  ElasticHQ
&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.elastichq.org/" rel="noopener noreferrer"&gt;http://www.elastichq.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ElasticHQ is an open source application that offers a simplified interface for managing and monitoring Elasticsearch clusters.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

    &lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/ElasticHQ/elasticsearch-HQ.git
    &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;elasticsearch-HQ

    &lt;span class="c"&gt;# Python 3 is required.&lt;/span&gt;
    &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;pip3 &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
    &lt;span class="nv"&gt;$ &lt;/span&gt;python3 application.py

    &lt;span class="c"&gt;# Access HQ with: http://localhost:5000&lt;/span&gt;
    &lt;span class="c"&gt;# If you're using docker version, access ES via host.docker.internal:9200&lt;/span&gt;


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

&lt;/div&gt;

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

&lt;p&gt;In this page we can check the cluster load, free space &amp;amp; heap usage. Also check the size of each indices, document count and total storage size.&lt;/p&gt;

&lt;p&gt;Another goodie is the &lt;code&gt;Diagnostics&lt;/code&gt; tab. HQ will highlight those metrics with potential risk and give you some advices. This can be a reference when you're troubleshooting or doing performance tuning on your elasticsearch cluster.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Cerebro
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/lmenezes/cerebro" rel="noopener noreferrer"&gt;https://github.com/lmenezes/cerebro&lt;/a&gt;&lt;/p&gt;

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

    &lt;span class="c"&gt;# Java 1.8 or newer is required. brew cask install java&lt;/span&gt;
    &lt;span class="c"&gt;# Download the latest tarball from https://github.com/lmenezes/cerebro/releases/latest&lt;/span&gt;
    &lt;span class="nv"&gt;$ &lt;/span&gt;wget https://github.com/lmenezes/cerebro/releases/download/v0.8.1/cerebro-0.8.1.tgz
    &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;tar &lt;/span&gt;zxvf cerebro-0.8.1.tgz
    &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;cerebro-0.8.1
    &lt;span class="nv"&gt;$ &lt;/span&gt;./bin/cerebro
    &lt;span class="c"&gt;# Open cerebro with http://localhost:9000&lt;/span&gt;
    &lt;span class="c"&gt;# If you're using docker version, access ES via host.docker.internal:9200&lt;/span&gt;


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

&lt;/div&gt;

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

&lt;p&gt;I usually use Cerebro to observe the index shards allocation. It's clear and intuitive.&lt;/p&gt;

&lt;p&gt;And the &lt;code&gt;cluster settings&lt;/code&gt;, &lt;code&gt;aliases&lt;/code&gt; and &lt;code&gt;index templates&lt;/code&gt; under more menu come handy when you need them.&lt;/p&gt;

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

</description>
      <category>elasticsearch</category>
      <category>elasticsearchhq</category>
      <category>cerebro</category>
    </item>
    <item>
      <title>sync.Pool</title>
      <dc:creator>Ash Wu</dc:creator>
      <pubDate>Thu, 19 Apr 2018 06:33:27 +0000</pubDate>
      <link>https://forem.com/hsatac/syncpool-34pd</link>
      <guid>https://forem.com/hsatac/syncpool-34pd</guid>
      <description>&lt;p&gt;Official document: [&lt;a href="https://godoc.org/sync#Pool"&gt;https://godoc.org/sync#Pool&lt;/a&gt;]&lt;/p&gt;

&lt;p&gt;The usage of &lt;code&gt;sync.Pool&lt;/code&gt; is a very common in high concurrency scenarios. You may create tons of goroutines and each of them allocates short-lived objects and later cause a slow GC.&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;sync.Pool&lt;/code&gt; we can avoid this. Objects inside the pool will be cleaned after GC without any notification, so &lt;code&gt;sync.Pool&lt;/code&gt; is not suitable for connection pool. &lt;/p&gt;

&lt;p&gt;The objects being &lt;code&gt;Put()&lt;/code&gt; back into the pool may be &lt;code&gt;Get()&lt;/code&gt; and reused before GC happens. This means you have the chance to &lt;code&gt;Get()&lt;/code&gt; a object with old values.&lt;/p&gt;

&lt;p&gt;Example here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"runtime"&lt;/span&gt;
    &lt;span class="s"&gt;"runtime/debug"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;newFunc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;newFunc&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;v1&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v1: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"modified v1: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// modified v1, put back to pool, before GC&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;v2&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v2: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// After GC&lt;/span&gt;
    &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetGCPercent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;v3&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"v3: %v&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So do remember to clean the object before you &lt;code&gt;Put()&lt;/code&gt; back, or init the object right after you &lt;code&gt;Get()&lt;/code&gt; to prevent any accident.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
  </channel>
</rss>
