<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Tech on Alan Zhan Blog</title>
    <link>https://alanzhan.dev/en/categories/tech/</link>
    <description>Recent content in Tech on Alan Zhan Blog</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 12 Mar 2023 18:04:41 +0800</lastBuildDate>
    <atom:link href="https://alanzhan.dev/en/categories/tech/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Building a Private GKE Cluster with Terraform</title>
      <link>https://alanzhan.dev/en/post/2023-03-12-terraform-private-gke/</link>
      <pubDate>Sun, 12 Mar 2023 18:04:41 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2023-03-12-terraform-private-gke/</guid>
      <description>&lt;p&gt;Let&amp;rsquo;s spend about ten minutes together — I&amp;rsquo;ll walk you through using Terraform to build a private GKE Cluster step by step!&lt;/p&gt;&#xA;&lt;h2 id=&#34;setting-up-gcp&#34;&gt;Setting Up GCP&lt;/h2&gt;&#xA;&lt;p&gt;&#xA;  &lt;img src=&#34;https://alanzhan.dev/2023-03-12-terraform-private-gke/create-service-account.jpg&#34; alt=&#34;Create Service Account and Key&#34;&gt;&#xA;&#xA;&lt;/p&gt;&#xA;&lt;h3 id=&#34;create-a-service-account&#34;&gt;Create a Service Account&lt;/h3&gt;&#xA;&lt;p&gt;First, go to the Google Cloud console and create a Service Account for Terraform to use. Follow steps 1, 2, and 3 in the diagram above. If you already have a Service Account, you can skip this step.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Core Component: Kubelet</title>
      <link>https://alanzhan.dev/en/post/2022-08-30-kubernetes-kubelet/</link>
      <pubDate>Tue, 30 Aug 2022 20:56:08 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-08-30-kubernetes-kubelet/</guid>
      <description>&lt;h1 id=&#34;kubelet-architecture&#34;&gt;Kubelet Architecture&lt;/h1&gt;&#xA;&lt;p&gt;As shown in the kubelet internal component structure diagram below, Kubelet is composed of many internal components:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Kubelet API: Including the authenticated API on port 10250, cAdvisor API on port 4194, read-only API on port 10255, and health check API on port 10248.&lt;/li&gt;&#xA;&lt;li&gt;syncLoop: Receives Pod updates from the API or manifest directories, sends them to podWorkers for processing, extensively using channels for async request handling.&lt;/li&gt;&#xA;&lt;li&gt;Auxiliary managers: Such as cAdvisor, PLEG, Volume Manager, etc., handling work outside of syncLoop.&lt;/li&gt;&#xA;&lt;li&gt;CRI: Container Runtime Interface, responsible for communicating with container runtime shims.&lt;/li&gt;&#xA;&lt;li&gt;Container runtimes: Such as dockershim, rkt, etc.&lt;/li&gt;&#xA;&lt;li&gt;Network plugins: Currently supports CNI and kubenet.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&#xA;  &lt;img src=&#34;https://alanzhan.dev/2022-08-30-kubernetes-kubelet/architecture.png&#34; alt=&#34;kubelet architecture&#34;&gt;&#xA;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Core Component: Controller Manager</title>
      <link>https://alanzhan.dev/en/post/2022-07-30-kubenetes-controller-manager/</link>
      <pubDate>Sat, 30 Jul 2022 20:07:01 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-07-30-kubenetes-controller-manager/</guid>
      <description>&lt;p&gt;Controller Manager is the automation control center of a Kubernetes cluster, containing over 30 controllers that manage Pod-related, network-related, storage-related operations, and more. Most controllers work similarly — each controller is a control loop responsible for watching its corresponding resources through the API server, deciding on the next action based on the object&amp;rsquo;s state, and driving it toward the desired state.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Controller Manager is the brain of the cluster and the key to keeping it running.&lt;/li&gt;&#xA;&lt;li&gt;Its role is to ensure Kubernetes follows the declarative system specification, keeping the system&amp;rsquo;s Actual State consistent with the user-defined Desired State.&lt;/li&gt;&#xA;&lt;li&gt;Controller Manager is a combination of multiple controllers. Each controller is a control loop responsible for watching its managed objects and completing configuration when objects change.&lt;/li&gt;&#xA;&lt;li&gt;Failed controller configurations typically trigger automatic retries. Through the controller&amp;rsquo;s continuous retry mechanism, the entire cluster ensures Eventual Consistency.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;controller-workflow&#34;&gt;Controller Workflow&lt;/h1&gt;&#xA;&lt;p&gt;&#xA;  &lt;img src=&#34;https://alanzhan.dev/2022-07-30-kubenetes-controller-manager/controller-flow.png&#34; alt=&#34;&#34;&gt;&#xA;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes - Node Maintenance and Pod Migration</title>
      <link>https://alanzhan.dev/en/post/2022-07-10-kubernetes-cordon-drain/</link>
      <pubDate>Sun, 10 Jul 2022 18:19:11 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-07-10-kubernetes-cordon-drain/</guid>
      <description>&lt;p&gt;Our company recently discovered machines on GKE with particularly low resource utilization. Those unused resources are still costing money, so we created a new Node Pool with lower and cheaper resources, then used Cordon + Drain (or manually deleted Pods) to reschedule Pods onto the new Node Pool. On GKE, simply deleting the old Node Pool would achieve the same result, but we chose the safer approach.&lt;/p&gt;&#xA;&lt;p&gt;This essentially marks a Node as unschedulable, then lets Pods migrate to the expected hosts. Let&amp;rsquo;s discuss how to safely handle node failures or upgrades.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Core Component: Scheduler</title>
      <link>https://alanzhan.dev/en/post/2022-05-16-kubernetes-scheduler/</link>
      <pubDate>Mon, 16 May 2022 22:40:48 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-05-16-kubernetes-scheduler/</guid>
      <description>&lt;p&gt;Strictly speaking, the Scheduler is a special type of Controller — its working principle is no different from other controllers.&lt;/p&gt;&#xA;&lt;p&gt;The Scheduler&amp;rsquo;s special responsibility is to monitor all unscheduled Pods in the cluster and obtain the health status and resource usage of all nodes, selecting the best node for each pending Pod to complete scheduling.&lt;/p&gt;&#xA;&lt;p&gt;kube-scheduler is responsible for assigning and scheduling Pods to nodes within the cluster. It watches kube-apiserver for Pods that haven&amp;rsquo;t been assigned to a Node, then assigns nodes to these Pods based on scheduling policies (by updating the Pod&amp;rsquo;s NodeName field).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Core Component: API Server</title>
      <link>https://alanzhan.dev/en/post/2022-04-24-kubernetes-api-server/</link>
      <pubDate>Sun, 24 Apr 2022 19:07:12 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-04-24-kubernetes-api-server/</guid>
      <description>&lt;h1 id=&#34;api-server&#34;&gt;API Server&lt;/h1&gt;&#xA;&lt;p&gt;kube-apiserver is one of the most important core components of Kubernetes, providing the following key features:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Cluster management REST API, including authentication, authorization, data validation, and cluster state changes&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Authentication&lt;/li&gt;&#xA;&lt;li&gt;Authorization&lt;/li&gt;&#xA;&lt;li&gt;Admission (Mutating &amp;amp; Validating)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Acts as the data exchange and communication hub between other modules. Other modules can only query or modify data through the API Server — only the API Server can directly operate on etcd.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;kube-apiserver supports HTTPS (default port 6443) and HTTP API (default listening on 127.0.0.1:8080). The HTTP API is insecure with no authentication or authorization mechanism — it&amp;rsquo;s not recommended for production environments.&lt;/p&gt;</description>
    </item>
    <item>
      <title>MongoDB Index Best Practices</title>
      <link>https://alanzhan.dev/en/post/2022-04-10-mongodb-index-best-practice/</link>
      <pubDate>Sun, 10 Apr 2022 16:19:10 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-04-10-mongodb-index-best-practice/</guid>
      <description>&lt;p&gt;After the sorted operation OOM incident in production from the previous post, I realized my understanding of MongoDB indexes wasn&amp;rsquo;t as deep as it should be. I started searching extensively and finally organized some key points. Some were covered in the previous post — feel free to review &lt;a href=&#34;https://alanzhan.dev/en/post/2022-03-20-mongodb-sorted-operation-oom/&#34;&gt;MongoDB Sorted Operation OOM&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h1 id=&#34;when-to-use-indexes&#34;&gt;When to Use Indexes&lt;/h1&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;When you have sorting scenarios and in-memory sorting exceeds 32 MB.&lt;/li&gt;&#xA;&lt;li&gt;When a specific field has a uniqueness requirement.&lt;/li&gt;&#xA;&lt;li&gt;When the document count is large.&lt;/li&gt;&#xA;&lt;li&gt;Build indexes on high-cardinality fields.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;when-not-to-use-indexes&#34;&gt;When NOT to Use Indexes&lt;/h1&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;When an index cannot effectively filter data.&lt;/li&gt;&#xA;&lt;li&gt;Don&amp;rsquo;t set indexes on frequently updated fields.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;how-to-design-and-use-indexes&#34;&gt;How to Design and Use Indexes&lt;/h1&gt;&#xA;&lt;h2 id=&#34;use-compound-indexes-instead-of-single-field-indexes&#34;&gt;Use Compound Indexes Instead of Single Field Indexes&lt;/h2&gt;&#xA;&lt;p&gt;In MongoDB, a find query can only use one index at a time (in most scenarios). So if your use case frequently filters on multiple fields, use a Compound Index composed of multiple fields to match your query conditions.&lt;/p&gt;</description>
    </item>
    <item>
      <title>MongoDB Sorted Operation OOM</title>
      <link>https://alanzhan.dev/en/post/2022-03-20-mongodb-sorted-operation-oom/</link>
      <pubDate>Sun, 20 Mar 2022 15:11:15 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-03-20-mongodb-sorted-operation-oom/</guid>
      <description>&lt;p&gt;This is a rare case where I learned by working backward from a problem — I&amp;rsquo;d better document it well. Recently, our production environment hit a MongoDB sort operation limit with this specific error:&lt;/p&gt;&#xA;&lt;p&gt;MongoDB.Driver.MongoCommandException: Command find failed: Encountered non-retryable error during query :: caused by :: Executor error during find command :: caused by :: Sort operation used more than the maximum 33554432 bytes of RAM.&lt;/p&gt;&#xA;&lt;p&gt;Well, the problem has occurred. Let&amp;rsquo;s solve it first — so we added an index as an immediate fix. But what exactly is a MongoDB index?&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Core Component: etcd</title>
      <link>https://alanzhan.dev/en/post/2022-02-28-kubetnetes-etcd/</link>
      <pubDate>Mon, 28 Feb 2022 15:58:47 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-02-28-kubetnetes-etcd/</guid>
      <description>&lt;p&gt;In any system, what is the most important thing? The answer is simple: data. So I&amp;rsquo;m starting my deep dive with Kubernetes&amp;rsquo; database — etcd!&lt;/p&gt;&#xA;&lt;h1 id=&#34;what-is-etcd&#34;&gt;What is etcd?&lt;/h1&gt;&#xA;&lt;p&gt;etcd is a distributed key-value store developed by CoreOS based on the Raft algorithm. It can be used for service discovery, shared configuration, and consistency guarantees (such as database leader election, distributed locks, etc.).&lt;/p&gt;&#xA;&lt;p&gt;In distributed systems, managing state across nodes has always been challenging. etcd is designed specifically for service discovery and registration in cluster environments. It provides features like data TTL expiration, data change monitoring, multi-value operations, directory watching, distributed lock atomic operations, and more — making it easy to track and manage cluster node states.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Installing Kubernetes with Kubeadm - Twice</title>
      <link>https://alanzhan.dev/en/post/2022-02-20-reinstall-kubernetes-kubeadm/</link>
      <pubDate>Sun, 20 Feb 2022 15:04:19 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-02-20-reinstall-kubernetes-kubeadm/</guid>
      <description>&lt;p&gt;To better understand K8s through hands-on practice, I wanted to set up a K8s cluster myself. There are increasingly many ways to self-host K8s nowadays — minikube, Kubeadm, and more. I decided to go with Kubeadm, but the installation wasn&amp;rsquo;t exactly smooth. This post shares the problems I encountered and how I solved them.&lt;/p&gt;&#xA;&lt;h1 id=&#34;first-installation-of-kubeadm&#34;&gt;First Installation of Kubeadm&lt;/h1&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Install Ubuntu.&lt;/li&gt;&#xA;&lt;li&gt;Install Docker.&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Modify Docker&amp;rsquo;s cgroup settings to ensure the K8s and container runtime cgroup drivers match, preventing system instability.&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo vim /etc/docker/daemon.json&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;exec-opts&amp;#34;&lt;/span&gt;: [&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;native.cgroupdriver=systemd&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Restart Docker&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl restart docker&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Install Kubeadm.&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Allow iptables to inspect bridged traffic.&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;lt;&amp;lt;EOF | sudo tee /etc/modules-load.d/k8s.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;br_netfilter&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;EOF&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;lt;&amp;lt;EOF | sudo tee /etc/sysctl.d/k8s.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;net.bridge.bridge-nf-call-ip6tables = 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;net.bridge.bridge-nf-call-iptables = 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;EOF&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo sysctl --system&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Update apt and install packages required by K8s.&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get update&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install -y apt-transport-https ca-certificates curl&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Download the Google Cloud public signing key.&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Add the K8s apt repository.&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main&amp;#34;&lt;/span&gt; | sudo tee /etc/apt/sources.list.d/kubernetes.list&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Update the apt package index, install kubelet, kubeadm, and kubectl, and pin their versions.&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get update&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install -y kubelet kubeadm kubectl&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-mark hold kubelet kubeadm kubectl&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Initialize K8s.&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo kubeadm init&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Join worker nodes&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo kubeadm join 192.168.83.130:6443 --token token....  --discovery-token-ca-cert-hash sha256:......................&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Copy kubeconfig&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p &lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$HOME&lt;/span&gt;/.kube&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo cp -i /etc/kubernetes/admin.conf &lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$HOME&lt;/span&gt;/.kube/config&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo chown &lt;span style=&#34;color:#ff79c6&#34;&gt;$(&lt;/span&gt;id -u&lt;span style=&#34;color:#ff79c6&#34;&gt;)&lt;/span&gt;:&lt;span style=&#34;color:#ff79c6&#34;&gt;$(&lt;/span&gt;id -g&lt;span style=&#34;color:#ff79c6&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$HOME&lt;/span&gt;/.kube/config&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;k8s-nodes-not-ready&#34;&gt;K8s Nodes Not Ready&lt;/h2&gt;&#xA;&lt;p&gt;I finally got it installed! So I added the worker nodes to the cluster. After joining, just as I was about to start using K8s, I noticed all nodes were in NotReady status.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Fundamentals</title>
      <link>https://alanzhan.dev/en/post/2022-02-14-kubernetes-introduction/</link>
      <pubDate>Mon, 14 Feb 2022 21:48:40 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-02-14-kubernetes-introduction/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s finally time to dive deep into Kubernetes. Since Kubernetes is built with Go, I&amp;rsquo;ve already done some in-depth research on Go beforehand. I won&amp;rsquo;t be covering Docker and container technology here since I&amp;rsquo;ve already studied those extensively. If you&amp;rsquo;d like to see that content, let me know! From here on, I&amp;rsquo;ll be writing a series of articles focused on Kubernetes.&lt;/p&gt;&#xA;&lt;h1 id=&#34;kubernetes&#34;&gt;Kubernetes&lt;/h1&gt;&#xA;&lt;p&gt;What is Kubernetes (K8s)? K8s is the abbreviation for Kubernetes — because there are eight letters between &amp;ldquo;K&amp;rdquo; and &amp;ldquo;s.&amp;rdquo; It&amp;rsquo;s Google&amp;rsquo;s open-source container cluster management system, the open-source version of Google&amp;rsquo;s years of large-scale container management technology called Borg. Its main features include:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Golang Memory Management and GC In-Depth Analysis</title>
      <link>https://alanzhan.dev/en/post/2022-02-13-golang-memory-management/</link>
      <pubDate>Sun, 13 Feb 2022 14:42:09 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-02-13-golang-memory-management/</guid>
      <description>&lt;p&gt;A new year has arrived! After completing the analysis of &lt;a href=&#34;https://alanzhan.dev/en/post/2022-01-24-golang-goroutine/&#34;&gt;Golang Goroutine and GMP Model In-Depth Analysis&lt;/a&gt;, I gained a much more comprehensive understanding of the Go language. But after learning about GMP, aren&amp;rsquo;t we still missing the memory management aspect? So today, let&amp;rsquo;s dive deep into how Go manages its memory.&lt;/p&gt;&#xA;&lt;h1 id=&#34;the-memory-management-debate&#34;&gt;The Memory Management Debate&lt;/h1&gt;&#xA;&lt;p&gt;When it comes to memory management, there&amp;rsquo;s been a long-standing debate: who should manage memory — the machine or the developer? Whether it&amp;rsquo;s machine-managed or human-managed, everyone agrees that memory management is critically important, but opinions diverge:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Golang Goroutine and GMP Model In-Depth Analysis</title>
      <link>https://alanzhan.dev/en/post/2022-01-24-golang-goroutine/</link>
      <pubDate>Mon, 24 Jan 2022 20:24:58 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-01-24-golang-goroutine/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve been studying Kubernetes recently, so I need to become good friends with the Go language. While reading, I came across goroutines, but couldn&amp;rsquo;t fully understand where they came from and why they exist. So before we dive deep into goroutines, we should first learn some history — this will give us a more comprehensive understanding of the principles and design philosophy behind goroutines.&lt;/p&gt;&#xA;&lt;h1 id=&#34;the-origin-of-golangs-scheduler&#34;&gt;The Origin of Golang&amp;rsquo;s Scheduler&lt;/h1&gt;&#xA;&lt;h2 id=&#34;the-single-process-era&#34;&gt;The Single-Process Era&lt;/h2&gt;&#xA;&lt;p&gt;We know that software runs on top of the operating system, and the CPU does the actual computation. In early operating systems, each program was a process, and the next process could only run after the current one finished.&lt;/p&gt;</description>
    </item>
    <item>
      <title>10 Dockerfile Best Practices</title>
      <link>https://alanzhan.dev/en/post/2022-01-16-dockerfile-best-practices/</link>
      <pubDate>Sun, 16 Jan 2022 16:55:15 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-01-16-dockerfile-best-practices/</guid>
      <description>&lt;p&gt;I was recently organizing Docker knowledge for myself and came across Dockerfile best practices. I planned to summarize them, but then I found that the official documentation already has best practices, so I decided to translate them and add my own insights.&lt;/p&gt;&#xA;&lt;h1 id=&#34;containers-should-be-ephemeral&#34;&gt;Containers Should Be Ephemeral&lt;/h1&gt;&#xA;&lt;p&gt;Containers built from a &lt;code&gt;Dockerfile&lt;/code&gt; should be as ephemeral as possible. &amp;ldquo;Ephemeral&amp;rdquo; here means they can be started quickly and stopped quickly.&lt;/p&gt;&#xA;&lt;h1 id=&#34;understand-the-build-context&#34;&gt;Understand the Build Context&lt;/h1&gt;&#xA;&lt;p&gt;Including files that aren&amp;rsquo;t needed to build the image results in a larger build context and larger image. This increases build time, pull/push time, and the runtime size of the container.&lt;/p&gt;</description>
    </item>
    <item>
      <title>GitHub Pages Custom Domain Setup</title>
      <link>https://alanzhan.dev/en/post/2022-01-09-github-pages-custom-domain/</link>
      <pubDate>Sun, 09 Jan 2022 14:58:58 +0800</pubDate>
      <guid>https://alanzhan.dev/en/post/2022-01-09-github-pages-custom-domain/</guid>
      <description>&lt;p&gt;I recently switched my domain name, so I decided to take some notes to help everyone easily set up their own GitHub Pages custom domain.&lt;/p&gt;&#xA;&lt;h1 id=&#34;step-1-purchase-a-domain&#34;&gt;Step 1: Purchase a Domain&lt;/h1&gt;&#xA;&lt;p&gt;First, purchase the domain name you want. I bought mine from Google Domains. If you have a preferred domain registrar, feel free to use that. This guide uses Google Domains as an example.&lt;/p&gt;&#xA;&lt;h1 id=&#34;step-2-add-a-cname-record-in-dns-settings&#34;&gt;Step 2: Add a CNAME Record in DNS Settings&lt;/h1&gt;&#xA;&lt;p&gt;After purchasing the domain, you need to configure the DNS settings. Follow the diagram below to set things up.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
