<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Technical on Yungen's blog</title><link>https://yungen.dev/blog/technical/</link><description>Recent content in Technical on Yungen's blog</description><generator>Hugo</generator><language>en-US</language><copyright>Copyright © 2020, Yung-En Lu.</copyright><lastBuildDate>Sat, 11 Apr 2026 22:29:22 -0500</lastBuildDate><atom:link href="https://yungen.dev/blog/technical/index.xml" rel="self" type="application/rss+xml"/><item><title>My MacBook Setup</title><link>https://yungen.dev/my-macbook-setup/</link><pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate><guid>https://yungen.dev/my-macbook-setup/</guid><description>&lt;p&gt;My philosophy for my setup is to keep things minimal. I never install an app just because “everyone uses it.” Instead of one big bloated app that does a lot of things averagely, I prefer multiple small apps that each do one thing well. I wrote this to keep track of what I’ve installed and to help me re-examine which apps I really need.&lt;/p&gt;
&lt;h1 id="productivity"&gt;Productivity&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Obsidian&lt;/strong&gt;: Notes, writings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Notion&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typora&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Antinote&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Claude&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="development"&gt;Development&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Orbstack&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Postman&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1Password&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ghostty&lt;/strong&gt;: I previously used Warp, but Warp kept pushing its AI features. I prefer a more minimal terminal app.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VirtualBox&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VSCode&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DBngin&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="work"&gt;Work&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Word&lt;/strong&gt;, &lt;strong&gt;PowerPoint&lt;/strong&gt;, &lt;strong&gt;Excel&lt;/strong&gt; : I might not need these in the future&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zoom&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Slack&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="utils"&gt;Utils&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AdGuard&lt;/strong&gt;: I bought the lifetime subscription during Black Friday sales. uBlock might be an alternative.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AppCleaner&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Karabiner-Elements&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keka&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;October&lt;/strong&gt;: A tool to sync Kobo eReader highlights to Readwise&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CleanShot X&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailscale&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maccy&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="personal"&gt;Personal&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Anki&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Calibre&lt;/strong&gt;: I personally own a Kobo eReader; an essential app for sideloading books&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IINA&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reader&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spotify&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="cli-tools"&gt;CLI tools&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;atiun&lt;/li&gt;
&lt;li&gt;docker&lt;/li&gt;
&lt;li&gt;docker-compose&lt;/li&gt;
&lt;li&gt;fd&lt;/li&gt;
&lt;li&gt;fnm&lt;/li&gt;
&lt;li&gt;fzf&lt;/li&gt;
&lt;li&gt;go&lt;/li&gt;
&lt;li&gt;hugo&lt;/li&gt;
&lt;li&gt;jq&lt;/li&gt;
&lt;li&gt;k9s&lt;/li&gt;
&lt;li&gt;lazygit&lt;/li&gt;
&lt;li&gt;neovim&lt;/li&gt;
&lt;li&gt;pnpm&lt;/li&gt;
&lt;li&gt;ripgrep&lt;/li&gt;
&lt;li&gt;tree&lt;/li&gt;
&lt;li&gt;uv&lt;/li&gt;
&lt;li&gt;wget&lt;/li&gt;
&lt;li&gt;topgrade&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mise.jdx.dev/"&gt;Home | mise-en-place&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Terraform short note</title><link>https://yungen.dev/terraform-short-note/</link><pubDate>Sun, 26 Feb 2023 00:00:00 +0000</pubDate><guid>https://yungen.dev/terraform-short-note/</guid><description>&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;在使用雲端服務時我們通常會使用雲端平台提供 GUI 介面去設定並使用雲端服務，但這樣有個缺點就是使用 GUI 設定很難被紀錄、重現，假設今天我架設一台 VM 更動了 20 幾個設定 ，日後我想要再設定另一台一模一樣的 VM 就會很麻煩，又或著我使用多個不同的雲端服務建立一個環境我希望其他人也能建立一個跟我一樣的環境。這時候我們就可以使用 Terraform 這個工具來達到 &lt;a href="https://en.wikipedia.org/wiki/Infrastructure_as_Code"&gt;Infrastructure as Code&lt;/a&gt;。我們可以使用 Code 來建置、更改並版本紀錄我們的 Infrastructure。&lt;/p&gt;
&lt;h1 id="hclhashicorp-configuration-language"&gt;HCL(Hashicorp Configuration Language)&lt;/h1&gt;
&lt;p&gt;Terraform 主要使用 HCL 來設定雲端服務，HCL 主要用來描述你想要設定的 &lt;a href="https://developer.hashicorp.com/terraform/language/resources"&gt;resource&lt;/a&gt; ，例如以下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;resource&lt;/span&gt; &lt;span style="color:#a6e3a1"&gt;&amp;#34;gpc_vpc&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e3a1"&gt;&amp;#34;main&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;2&lt;/span&gt;&lt;span&gt; &lt;span style="color:#f38ba8"&gt;cidr_block&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;=&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;var.base_cidr_block&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;3&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;4&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;5&lt;/span&gt;&lt;span&gt;&lt;span style="color:#f38ba8"&gt;&amp;lt;BLOCK&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;TYPE&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e3a1"&gt;&amp;#34;&amp;lt;BLOCK LABEL&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e3a1"&gt;&amp;#34;&amp;lt;BLOCK LABEL&amp;gt;&amp;#34;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;6&lt;/span&gt;&lt;span&gt; &lt;span style="color:#f38ba8"&gt;#&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;Block&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;body&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;7&lt;/span&gt;&lt;span&gt; &lt;span style="color:#f38ba8"&gt;&amp;lt;IDENTIFIER&amp;gt;&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;=&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;&amp;lt;EXPRESSION&amp;gt;&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;#&lt;/span&gt; &lt;span style="color:#f38ba8"&gt;Argument&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;8&lt;/span&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果你使用 vscode 可以用這個 &lt;a href="https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform"&gt;extension&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="install"&gt;Install&lt;/h1&gt;
&lt;p&gt;請參考官方 &lt;a href="https://developer.hashicorp.com/terraform/downloads"&gt;連結&lt;/a&gt;&lt;/p&gt;</description></item><item><title>kubernetes local dev</title><link>https://yungen.dev/kubernetes-local-dev/</link><pubDate>Tue, 29 Nov 2022 00:00:00 +0000</pubDate><guid>https://yungen.dev/kubernetes-local-dev/</guid><description>&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;在開發 kubernetes 相關的程式時為了確保程式能正確運行，需要一個 kubernetes 環境方便我們測試。我們不太可能每次測試都要另外開一個 gke ，太麻煩且浪費錢了，所以我們需要一些工具幫助我們在本地端架設 kubernetes cluster 來測試。&lt;/p&gt;
&lt;p&gt;在本地端架設 kubernetes 有許多種方法下面列舉出一些較多人使用的工具&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://minikube.sigs.k8s.io/docs/"&gt;minikube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://k3d.io/"&gt;k3d&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kind.sigs.k8s.io"&gt;kind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rancherdesktop.io"&gt;rancherdesktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/abiosoft/colima"&gt;colima&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接下來會介紹如何安裝以及使用 minikube 以及 rancherdesktop&lt;/p&gt;
&lt;h1 id="minikube"&gt;minikube&lt;/h1&gt;
&lt;h2 id="prerequisite"&gt;Prerequisite&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;安裝 docker 或 nerdctl&lt;/li&gt;
&lt;li&gt;安裝 kubectl&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安裝-minikube"&gt;安裝 minikube&lt;/h2&gt;
&lt;h3 id="mac"&gt;mac&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;brew install minikube
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="linuxwsl"&gt;linux(WSL)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;curl -LO &amp;lt;https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;2&lt;/span&gt;&lt;span&gt;sudo install minikube-linux-amd64 /usr/local/bin/minikube
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更多安裝方法請參考 &lt;a href="https://minikube.sigs.k8s.io/docs/start/"&gt;https://minikube.sigs.k8s.io/docs/start/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="啟動"&gt;啟動&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;minikube start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="結束"&gt;結束&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;minikube stop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="檢查-kubectl-context"&gt;檢查 kubectl context&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;kubectl config get-contexts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="設定-kubectl-context"&gt;設定 kubectl context&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;kubectl config use-context &amp;lt;context-name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id="rancher-desktop"&gt;rancher desktop&lt;/h1&gt;
&lt;h2 id="prerequisite-1"&gt;Prerequisite&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;無&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="安裝-rancher-desktop"&gt;安裝 rancher desktop&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;直接下載&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;brew install --cask rancher
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="檢查-kubectl-context-1"&gt;檢查 kubectl context&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;kubectl config get-contexts
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="設定-kubectl-context-1"&gt;設定 kubectl context&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;kubectl config use-context &amp;lt;context-name&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id="build-and-deploy"&gt;build and deploy&lt;/h1&gt;
&lt;h2 id="minikube-1"&gt;minikube&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;&lt;span style="color:#89dceb"&gt;eval&lt;/span&gt; &lt;span style="color:#cba6f7"&gt;$(&lt;/span&gt;minikube docker-env&lt;span style="color:#cba6f7"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="確定-docker-context"&gt;確定 docker context&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f849c"&gt;1&lt;/span&gt;&lt;span&gt;docker context list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="deploy"&gt;deploy&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;kubernetes.yaml&lt;/code&gt;&lt;/p&gt;</description></item><item><title>MQTT short note</title><link>https://yungen.dev/mqtt-short-note/</link><pubDate>Fri, 18 Mar 2022 00:00:00 +0000</pubDate><guid>https://yungen.dev/mqtt-short-note/</guid><description>&lt;h1 id="what-is-mqtt"&gt;What is mqtt&lt;/h1&gt;
&lt;p&gt;mqtt 是個基於 Pub/Sub 模式的 protocol ，主要會由一個 message broker 與多個 client 組成。&lt;/p&gt;
&lt;h1 id="what-is-pubsub"&gt;What is Pub/Sub&lt;/h1&gt;
&lt;p&gt;在 Pub/Sub 的傳輸模式下訊息的傳輸不會以一對一的方式傳送訊息，而是將訊息發布到一個 Topic 中，而所有有訂閱該 Topic 的用戶都會收到訊息。可以想像為 slack 的頻道，我可以在 d1 中發訊息（發布訊息到 d1 這個 topic），而只會有在 d1 這個頻道的使用者收到訊息（有訂閱 d1 topic 的使用者）。不過在 Pub/Sub 模式下收到訊息不會知道是誰發佈的。（除非在訊息中有寫）&lt;/p&gt;
&lt;h2 id="mqtt-傳輸模式"&gt;MQTT 傳輸模式&lt;/h2&gt;
&lt;h3 id="qos"&gt;QOS&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;QoS 0: 最多一次傳送：client 傳送訊息後不在乎訊息是否真的有其他 client 端收到。&lt;/li&gt;
&lt;li&gt;QoS 1: 至少一次傳送：client 傳送訊息後會等待接收方回應，如果沒有回應則會重新再傳一次。（此方法可以確保訊息會送達，但不會確保訊息不會重複）&lt;/li&gt;
&lt;li&gt;QoS 2: 正好一次傳送：與 QoS 2 相似但會確保訊息不會重複。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="how"&gt;How&lt;/h1&gt;
&lt;p&gt;目前打算使用 emqx 作為 message broker ，讓所有使用者作為 client 端，同時 chat services 也會作為 client 發布訊息給所有 client 端。&lt;/p&gt;</description></item><item><title>kubernetes basics</title><link>https://yungen.dev/kubernetes-basics/</link><pubDate>Wed, 09 Mar 2022 00:00:00 +0000</pubDate><guid>https://yungen.dev/kubernetes-basics/</guid><description>&lt;h1 id="wow-docker-好方便那他跟-kubernetes-差在哪裡"&gt;Wow Docker 好方便！那他跟 kubernetes 差在哪裡？&lt;/h1&gt;
&lt;p&gt;首先，docker 是無法跟 kubernetes 比較的，docker 是運行 container 的一種方式，許多人會認為 docker == container == image ，但實際上 docker ≠ container ≠ image。&lt;/p&gt;
&lt;p&gt;在了解 kubernetes 前我們要先理解 container 到底是怎麼運作的。&lt;/p&gt;
&lt;h1 id="container--container-engine--container-runtime-"&gt;container 、 container engine 、 container runtime ???&lt;/h1&gt;
&lt;p&gt;docker 的基本概念可以參考下圖&lt;/p&gt;
&lt;p&gt;&lt;img src="kubernetes-basics-164b808d0b00542b6fb5ffe53980125e.png" alt=""&gt;&lt;/p&gt;
&lt;p&gt;當使用者輸入 &lt;code&gt;docker ...&lt;/code&gt; 其實是在告訴 docker engine(container engine) 使用者要跑一些 image 這時候 docker engine 就會告訴 containerd (container runtime) 該做什麼事（比如說要 pull image 、 建立 container 之類的）containerd 就會根據 docker engine 的指令做事。（備註： 圖中的 runc 其實也是 container runtime 因為 container runtime 有分 high level 與 low level &amp;hellip;）&lt;/p&gt;</description></item><item><title>gRPC short note</title><link>https://yungen.dev/grpc-short-note/</link><pubDate>Fri, 04 Mar 2022 00:00:00 +0000</pubDate><guid>https://yungen.dev/grpc-short-note/</guid><description>&lt;h1 id="what-is-grpc"&gt;What is gRPC&lt;/h1&gt;
&lt;p&gt;在了解什麼是 gRPC 之前需要先解釋一下什麼是 RPC(Remote Procedure Call)。RPC 是一種程式之間溝通的方式，A 程式可以呼叫 B 程式去執行一些 function ，也可以把他想像為在一個程式中呼叫另一個程式的 function 。gRPC 為 google 推出的一個 framework 能實現上述提到的功能。&lt;/p&gt;
&lt;h1 id="why"&gt;Why&lt;/h1&gt;
&lt;p&gt;未來如果要將 backend microservices 化，會遇到一個問題就是 services 之間要如何溝通，當然我們能夠沿用 HTTP 作為溝通的方式，但 HTTP 有幾個缺點：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;與 gRPC 相比、傳輸同一筆資料需要消耗更多頻寬。舉例：&lt;/p&gt;
&lt;p&gt;json: &lt;code&gt;{”id”:2}&lt;/code&gt; (9 bytes)&lt;/p&gt;
&lt;p&gt;xml: &lt;code&gt;&amp;lt;id&amp;gt;42&amp;lt;/id&amp;gt;&lt;/code&gt; (11 bytes)&lt;/p&gt;
&lt;p&gt;protobuf: &lt;code&gt;0x08 0x2a&lt;/code&gt; (2 bytes) → gRPC 的傳輸方式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;傳輸方式只有一種（client 發送 request, server 給予 response）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;hellip;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;總而言之 gRPC 的方式更適合 microservice 架構&lt;/p&gt;
&lt;p&gt;更詳細的比較可以參考這篇：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/zh-tw/aspnet/core/grpc/comparison?view=aspnetcore-6.0"&gt;比較 gRPC 服務與 HTTP API&lt;/a&gt;&lt;/p&gt;</description></item><item><title>traefik &amp; let’s encrypt</title><link>https://yungen.dev/traefik-lets-encrypt/</link><pubDate>Fri, 04 Feb 2022 00:00:00 +0000</pubDate><guid>https://yungen.dev/traefik-lets-encrypt/</guid><description>&lt;h1 id="前言"&gt;前言&lt;/h1&gt;
&lt;p&gt;在上一篇文章中介紹如何設置 reverse proxy ，這篇將會介紹如何使用 let’s encrypt 讓 traefik 支援 HTTPS 連線。&lt;/p&gt;
&lt;h1 id="簡單介紹-lets-encrypt"&gt;簡單介紹 let’s encrypt&lt;/h1&gt;
&lt;p&gt;let’s encrypt 是個憑證頒發機構，與其他憑證頒發機構不同的是 let’s encrypt 提供免費的憑證，只要客戶端達成某些條件，向 let’s encrypt 證明其擁有某個網域名時，let’s encrypt 就會免費提供數位憑證給客戶端。&lt;/p&gt;
&lt;h1 id="traefik--lets-encrypt"&gt;traefik &amp;amp; let’s encrypt&lt;/h1&gt;
&lt;p&gt;traefik 本身支援使用最常見的 TLS 憑證，也支援透過 &lt;a href="https://zh.wikipedia.org/wiki/%E8%87%AA%E5%8B%95%E6%86%91%E8%AD%89%E6%9B%B4%E6%96%B0%E7%92%B0%E5%A2%83"&gt;ACME&lt;/a&gt; 的方式向支援 ACME 頒發憑證的機構自動獲取數位憑證（此範例使用 let’s encrypt）。此外，let’s encrypt 所頒發的數位憑證有有效期限，traefik 會在到期時自動更新數位憑證。&lt;/p&gt;
&lt;h1 id="lets-encrypt-運作機制"&gt;let’s encrypt 運作機制&lt;/h1&gt;
&lt;p&gt;在申請憑證時，最重要的步驟就是向 let’s encrypt 證明你擁有此網域。let’s encrypt 有提供三種方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTTP-01 考驗：let’s encrypt 會給客戶端一個 token ，客戶端要將 此 token 放在網頁伺服器 &lt;code&gt;http://&amp;lt;YOUR_DOMAIN&amp;gt;/.well-known/acme-challenge/&amp;lt;TOKEN&amp;gt;&lt;/code&gt; 中，let’s encrypt 之後就會向該網址發送請求，若 let’s encrypt 成功拿到 token 後就會認定此網域的確為客戶所擁有，並頒發數位憑證。&lt;/li&gt;
&lt;li&gt;DNS-01 考驗：let’s encrypt 會給客戶端一組字串 ，客戶端將此字串以 TXT 紀錄放在 DNS 中，接著 let’s encrypt 就會去查詢相對應的 DNS TXT 紀錄。若有成功查詢到 TXT 紀錄，就會認定此網域的確為客戶所擁有，並頒發數位憑證。&lt;/li&gt;
&lt;li&gt;TLS-ALPN-01 考驗：此方法較為少見，詳細可參考 &lt;a href="https://letsencrypt.org/zh-tw/docs/challenge-types/"&gt;官網&lt;/a&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;traefik 支援以上三種驗證方式，且會在快到期時自動更新憑證。接下來的範例中會使用 HTTPS-01 以及 DNS-01 考驗。&lt;/p&gt;</description></item><item><title>traefik tutorial</title><link>https://yungen.dev/traefik-tutorial/</link><pubDate>Tue, 01 Feb 2022 00:00:00 +0000</pubDate><guid>https://yungen.dev/traefik-tutorial/</guid><description>&lt;h1 id="前言"&gt;前言&lt;/h1&gt;
&lt;p&gt;當我們在架設後端 service 的時候很常會遇到要將 service A 和 service B 放在同一個伺服器中運行，這時候會遇到一個問題：要如何設置 Endpoint 讓使用者能分別使用 service A 與 service B 呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方法ㄧ：將 service A 暴露（expose?）在 port A （例如：9000），將 service B 暴露在與 port A 不同的 port B （例如：3000），這樣使用者就能分別從 &amp;lt;伺服器 IP&amp;gt;:&amp;lt;portA&amp;gt; 、&amp;lt;伺服器 IP&amp;gt;:&amp;lt;portB&amp;gt; （例如：140.116.241.66:9000,140.116.241.66:3000）存取 service A 與 B&lt;/li&gt;
&lt;li&gt;方法二：使用 reverse proxy ，設置 reverse proxy 監聽 port C （例如：80），使用者只要向 &amp;lt;伺服器 IP&amp;gt;:&amp;lt;portC&amp;gt; 發送 request ， reverse proxy 會根據使用者請求分別將 request 轉送到不同的 service （例如：140.116.241.66:80/A → service A、140.116.241.66:80/B → service B）。以下文章會介紹如何使用 &lt;a href="https://traefik.io/traefik/"&gt;traefik&lt;/a&gt; 作為 reverse proxy&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="簡單介紹-traefik"&gt;簡單介紹 traefik&lt;/h1&gt;
&lt;p&gt;在 traefik 的官網中是如此介紹 traefik 的&lt;/p&gt;</description></item><item><title>Code-Prettifyer project</title><link>https://yungen.dev/code-prettifyer-project/</link><pubDate>Mon, 11 Jan 2021 00:00:00 +0000</pubDate><guid>https://yungen.dev/code-prettifyer-project/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;本篇內容主要是說明我如何用 Docker、traefik、nginx 軟體，以及 JavaScript、PHP、C⋯⋯等等程式語言，做出一個可以讓使用者透過網頁輸入自己的程式碼後，對其進行分析、檢查以及排版的網頁應用程式。&lt;/p&gt;
&lt;h2 id="概念發想"&gt;概念發想&lt;/h2&gt;
&lt;p&gt;因著我是大一才開始真正接觸程式，從編輯器開始接觸了 vim。因著 vim 的特性，可以自定義很多快捷鍵、以及安裝許多由其他人寫的 plugin。其中就有 plugin 可透過其他人寫的 &lt;a href="https://zh.wikipedia.org/wiki/Lint"&gt;linter&lt;/a&gt; 直接對程式碼進行分析，找出程式碼中可能存在的錯誤。這個 plugin 帶給我許多方便，可惜的是絕大部分的 linter 在 windows 環境安裝起來有點麻煩，為了能推廣 linter 給使用 windows 環境的朋友，我便有一個想法。就是做一個網頁使使用者只要複製貼上自己的程式碼，按一個鍵，就能輸出分析結果甚至格式化程式碼。&lt;/p&gt;
&lt;h2 id="過程"&gt;過程&lt;/h2&gt;
&lt;h3 id="伺服器"&gt;伺服器&lt;/h3&gt;
&lt;p&gt;要能架設網頁首先就是要有自己的伺服器，因著我手邊剛好有一台 raspberry pi 我就直接在上面安裝 ubuntu 20.4LTS。&lt;/p&gt;
&lt;p&gt;安裝完基本設定都搞定後，抱著好玩與嘗試的心態我沒有照原本的計畫直接在 raspberry 上安裝 web server 而是想要嘗試看看用 docker 來運行 web server，基本上我就照著官方給的 &lt;a href="https://docs.docker.com/engine/install/ubuntu/"&gt;資料&lt;/a&gt; 安裝就成功了。接著我照著其他人給的建議安裝了 &lt;a href="https://www.portainer.io/"&gt;portainer&lt;/a&gt; 讓我可以透過網頁 UI 來管理 docker。&lt;/p&gt;
&lt;p&gt;到目前為止，我只能透過內網連到我的伺服器，如果要從外面的網路連到伺服器的話就需要有一個固定 ip。因著我家裡是安裝中華電信的網路，所以我可以直接到他們的網站申請一組固定 ip。申請完後直接設定 raspberry pi 讓它能透夠 PPPoE 的方式上網。&lt;/p&gt;
&lt;p&gt;這時候我已經可以直接在外網 ssh 到伺服器，或是直接在瀏覽器輸入 ip 位址打開 portianer 頁面了。但如果其他要連到我的網頁的話就要輸入一串很難記的數字。為了讓我的網頁更好記得，我就在 name.com 上申請了自己網域名。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://i.imgur.com/U7f4Ahp.png" alt="my domain"&gt;&lt;/p&gt;
&lt;p&gt;申請完後在設定裡添加一個 A record 指向自己 server 的位址&lt;/p&gt;</description></item></channel></rss>