<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Davy's Blog]]></title><description><![CDATA[Memos, technologies, moods and stories inside.]]></description><link>https://blog.davy.tw/</link><image><url>https://blog.davy.tw/favicon.png</url><title>Davy&apos;s Blog</title><link>https://blog.davy.tw/</link></image><generator>Ghost 5.79</generator><lastBuildDate>Sat, 11 Apr 2026 06:32:42 GMT</lastBuildDate><atom:link href="https://blog.davy.tw/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[使用 cert-manager 透過 ACME 從 FreeIPA 簽發憑證]]></title><description><![CDATA[本文旨在透過 cert-manager 自動從 Ingress 獲取設定後，觸發 FreeIPA/BIND9 設定 DNS TXT RR 並在通過 DNS-01 驗證後，由 FreeIPA 簽發憑證並套用回 TLS Ingress 上的一條龍技巧……]]></description><link>https://blog.davy.tw/posts/automatically-sign-certificate-using-cert-manager-and-freeipa/</link><guid isPermaLink="false">669927175cd7770001511718</guid><category><![CDATA[DNS]]></category><category><![CDATA[cert-manager]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[K8s]]></category><category><![CDATA[FreeIPA]]></category><category><![CDATA[BIND9]]></category><category><![CDATA[ACME]]></category><category><![CDATA[DNS-01]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Sun, 21 Jul 2024 10:30:19 GMT</pubDate><media:content url="https://blog.davy.tw/content/images/2024/07/-------2024-07-21-182953.png" medium="image"/><content:encoded><![CDATA[<blockquote>
<img src="https://blog.davy.tw/content/images/2024/07/-------2024-07-21-182953.png" alt="&#x4F7F;&#x7528; cert-manager &#x900F;&#x904E; ACME &#x5F9E; FreeIPA &#x7C3D;&#x767C;&#x6191;&#x8B49;"><p>&#x672C;&#x7BC7; TL;DR &#x56E0;&#x5305;&#x542B;&#x8173;&#x672C;&#x53CA; K8s yaml &#x5167;&#x5BB9;&#x8F03;&#x9577;&#xFF0C;&#x6709;&#x8208;&#x8DA3;&#x76F4;&#x63A5;&#x95B1;&#x8B80;&#x5168;&#x6587;&#x7684;&#x8B80;&#x8005;&#x53EF;&#x4EE5;<a href="#%E5%89%8D%E8%A8%80">&#x6309;&#x6B64;&#x8DF3;&#x5230;&#x6B63;&#x6587;</a>&#x3002;</p>
</blockquote>
<h1 id="tldr">TL;DR</h1>
<p>&#x5206;&#x6210; FreeIPA &#x8207; cert-manager &#x5169;&#x500B;&#x90E8;&#x5206;&#x8A2D;&#x5B9A;&#xFF1A;</p>
<h2 id="freeipa">FreeIPA</h2>
<pre><code class="language-txt"># ipa-acme-manage enable
# tsig-keygen -a hmac-sha512 cert-manager-acme | tee -a /etc/named/ipa-ext.conf
# systemctl restart named-pkcs11.service || systemctl restart named.service
# ipa dnszone-mod ${IPA_DNS_ZONE} --dynamic-update=True \
    --update-policy=&apos;grant cert-manager-acme wildcard * TXT;&apos;
</code></pre>
<p>&#x9806;&#x4FBF;&#x8A18;&#x4E0B;&#x5370;&#x51FA;&#x4F86;&#x7684; TSIG Key Secret&#x3002;</p>
<h2 id="cert-manager">cert-manager</h2>
<pre><code class="language-yaml">---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
  namespace: cert-manager
  name: ipa-tsig
data:
  cert-manager-acme: ${TSIG_SECRET_IN_BASE64}
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: ipa
spec:
  acme:
    caBundle: ${IPA_CA_CERT_IN_BASE64}
    privateKeySecretRef:
      name: ipa-acme-account-key
    server: https://${IPA_CA_SERVER}/acme/directory
    solvers:
    - dns01:
        rfc2136:
          nameserver: ${IPA_NS_IP}
          tsigAlgorithm: HMACSHA512
          tsigKeyName: cert-manager-acme
          tsigSecretSecretRef:
            key: cert-manager-acme
            name: ipa-tsig
      selector:
        dnsZones:
        - ${IPA_DNS_ZONE}
</code></pre>
<p>&#x5B8C;&#x6210;&#x3002;&#x5982;&#x679C;&#x8981;&#x5F9E; Ingress &#x81EA;&#x52D5;&#x767C;&#x6191;&#x8B49;&#x7684;&#x8A71;&#x8981;&#x8A18;&#x5F97;&#x52A0;&#x4E0A; <code>cert-manager.io/cluster-issuer: ipa</code> &#x7684; annotation&#x3002;</p>
<h1 id="%E5%89%8D%E8%A8%80">&#x524D;&#x8A00;</h1>
<p>&#x6211;&#x5011;&#x5728;&#x7BA1;&#x7406; Kubernetes<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> &#x7684;&#x6642;&#x5019;&#x5E38;&#x5E38;&#x6703;&#x9700;&#x8981;&#x63D0;&#x4F9B;&#x4E00;&#x500B; TLS Ingress<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>&#xFF0C;&#x5728;&#x6C92;&#x6709;&#x81EA;&#x52D5;&#x5316;&#x5DE5;&#x5177;&#x7684;&#x5354;&#x52A9;&#x4E0B;&#xFF0C;&#x6211;&#x5011;&#x6703;&#x9700;&#x8981;&#x624B;&#x52D5;&#x5C07;&#x6191;&#x8B49;&#x53CA;&#x91D1;&#x9470;&#x585E;&#x9032; Cluster &#x88E1;&#x3002;</p>
<p>&#x6B64;&#x6642; cert-manager<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> &#x5C31;&#x80FD;&#x5E6B;&#x6211;&#x5011;&#x8655;&#x7406;&#x81EA;&#x52D5;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#x7684;&#x554F;&#x984C;&#xFF0C;cert-manager &#x652F;&#x63F4;&#x900F;&#x904E; ACME<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup> &#x4F86;&#x5B8C;&#x6210;&#x81EA;&#x52D5;&#x5316;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#x3002;&#x901A;&#x5E38;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x80FD;&#x6703;&#x62FF;&#x4F86;&#x7C3D;&#x767C; Let&apos;s Encrypt<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup> &#x7684;&#x6191;&#x8B49;&#xFF0C;&#x4F46;&#x5982;&#x4F55;&#x8B93; Let&apos;s Encrypt &#x901A;&#x904E;&#x9A57;&#x8B49;&#x5C31;&#x6703;&#x662F;&#x500B;&#x554F;&#x984C;&#xFF0C;cert-manager &#x540C;&#x6642;&#x652F;&#x63F4;&#x4E86; HTTP-01<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup> &#x53CA; DNS-01<sup class="footnote-ref"><a href="#fn7" id="fnref7">[7]</a></sup> &#x5169;&#x7A2E;&#x65B9;&#x5F0F;&#x3002;</p>
<p>&#x4ECA;&#x5929;&#x60F3;&#x8981;&#x4F86;&#x8DDF;&#x5927;&#x5BB6;&#x804A;&#x804A;&#xFF0C;&#x5982;&#x679C;&#x60F3;&#x900F;&#x904E; cert-manager &#x81EA;&#x52D5;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#x7684;&#x8A71;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x600E;&#x9EBC;&#x8A2D;&#x5B9A;&#x3002;&#x672C;&#x7BC7;&#x4EE5;&#x60F3;&#x8981;&#x8B93; FreeIPA<sup class="footnote-ref"><a href="#fn8" id="fnref8">[8]</a></sup> &#x4F5C;&#x70BA;&#x6191;&#x8B49;&#x7C3D;&#x767C;&#x8005;&#xFF0C;&#x800C;&#x4E14;&#x900F;&#x904E; DNS-01 &#x901A;&#x904E;&#x9A57;&#x8B49;&#x7576;&#x4F5C;&#x76EE;&#x6A19;&#x4F86;&#x9032;&#x884C;&#xFF08;&#x9069;&#x7528;&#x65BC;&#x7528; FreeIPA &#x7BA1;&#x7406; DNS zone &#x7684;&#x5834;&#x666F;&#xFF0C;&#x6240;&#x4EE5;&#x4F60;&#x60F3;&#x7528; Let&apos;s Encrypt &#x7C3D;&#x767C;&#x6191;&#x8B49;&#x4E5F;&#x53EF;&#x4EE5;&#xFF09;&#xFF1A;</p>
<h1 id="freeipa-dns">FreeIPA DNS</h1>
<p>&#x7531;&#x65BC;&#x6211;&#x5011;&#x6253;&#x7B97;&#x63A1;&#x7528; DNS-01 &#x4F5C;&#x70BA; ACME &#x7684;&#x8A8D;&#x8B49;&#x624B;&#x6BB5;&#xFF0C;&#x6211;&#x5011;&#x5F97;&#x5148;&#x4F86;&#x641E;&#x5B9A;&#x5982;&#x4F55;&#x8B93; cert-manager &#x81EA;&#x52D5;&#x4F86;&#x4FEE;&#x6539; FreeIPA &#x7684; DNS &#x8A18;&#x9304;&#x3002;</p>
<p>FreeIPA &#x4F7F;&#x7528; BIND9<sup class="footnote-ref"><a href="#fn9" id="fnref9">[9]</a></sup> &#x4F5C;&#x70BA;&#x5176; DNS &#x7684;&#x89E3;&#x6C7A;&#x65B9;&#x6848;&#xFF0C;&#x7531;&#x65BC; BIND &#x8207; cert-manager &#x90FD;&#x652F;&#x63F4;<sup class="footnote-ref"><a href="#fn10" id="fnref10">[10]</a></sup> RFC-2136<sup class="footnote-ref"><a href="#fn11" id="fnref11">[11]</a></sup>&#xFF0C;&#x56E0;&#x6B64;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E; <code>UPDATE</code> &#x6307;&#x4EE4;&#x4F86;&#x66F4;&#x65B0; RR<sup class="footnote-ref"><a href="#fn12" id="fnref12">[12]</a></sup>&#x3002;&#x800C;&#x70BA;&#x4E86;&#x8B93; FreeIPA &#x7684; BIND &#x78BA;&#x8A8D;&#x9019;&#x500B;&#x66F4;&#x65B0;&#x7684;&#x6307;&#x4EE4;&#x662F;&#x5F9E;&#x88AB;&#x6388;&#x6B0A;&#x7684; cert-manager &#x4F86;&#x7684;&#xFF0C;&#x6211;&#x5011;&#x9084;&#x5FC5;&#x9808;&#x900F;&#x904E; TSIG<sup class="footnote-ref"><a href="#fn13" id="fnref13">[13]</a></sup> RR &#x4F86;&#x9032;&#x884C;&#x7C3D;&#x540D;&#x8A8D;&#x8B49;&#x3002;</p>
<h2 id="tsig-secret-key">TSIG Secret Key</h2>
<p>&#x8AAA;&#x5230;&#x7C3D;&#x540D;&#xFF0C;&#x5C31;&#x5FC5;&#x9808;&#x8981;&#x6709;&#x4E00;&#x500B;&#x53EF;&#x4EE5;&#x62FF;&#x4F86;&#x7C3D;&#x540D;<sup class="footnote-ref"><a href="#fn14" id="fnref14">[14]</a></sup>&#x7684; Secret Key&#xFF0C;&#x65BC;&#x662F;&#x8B93;&#x6211;&#x5011;&#x5F9E;&#x5EFA;&#x7ACB;&#x9019;&#x628A;&#x91D1;&#x9470;&#x958B;&#x59CB;&#xFF1A;</p>
<pre><code class="language-txt"># export TSIG_KEY_NAME=cert-manager-acme
# tsig-keygen -a hmac-sha512 ${TSIG_KEY_NAME} | tee -a /etc/named/ipa-ext.conf
key &quot;cert-manager-acme&quot; {
        algorithm hmac-sha512;
        secret &quot;&lt;...base64 encoded secret here...&gt;&quot;;
};
# systemctl restart named.service || systemctl restart named-pkcs11.service
#
</code></pre>
<p>&#x8ACB;&#x81EA;&#x884C;&#x5C07; <code>${TSIG_KEY_NAME}</code> &#x66FF;&#x63DB;&#x6210;&#x60F3;&#x8981;&#x7684;&#x91D1;&#x9470;&#x540D;&#x7A31;&#xFF0C;&#x50CF;&#x7B46;&#x8005;&#x662F;&#x4F7F;&#x7528;&#x5BB9;&#x6613;&#x8B58;&#x5225;&#x7684; <code>cert-manager-acme</code>&#xFF0C;&#x8868;&#x793A;&#x9019;&#x628A;&#x91D1;&#x9470;&#x662F;&#x7D66; cert-manager &#x4F5C;&#x70BA; ACME &#x7528;&#x7684;&#x91D1;&#x9470;&#x3002;</p>
<p>&#x53E6;&#x5916;&#xFF0C;&#x8F38;&#x51FA;&#x7684; <code>secret</code> &#x5167;&#x5BB9;&#x8ACB;&#x8A18;&#x4E0B;&#x4F86;&#xFF0C;&#x6B64;&#x70BA; TSIG Secret Key&#xFF0C;&#x5F8C;&#x9762;&#x6703;&#x7528; <code>${TSIG_SECRET}</code> &#x8868;&#x793A;&#xFF0C;&#x5728;&#x8A2D;&#x5B9A; cert-manager &#x6642;&#x9084;&#x6703;&#x7528;&#x5230;&#x3002;&#x6211;&#x5011;&#x5728;&#x9019;&#x88E1;&#x5EFA;&#x7ACB;&#x4E86;&#x4E00;&#x628A;&#x4F7F;&#x7528; HMAC-SHA512<sup class="footnote-ref"><a href="#fn15" id="fnref15">[15]</a></sup> &#x4F5C;&#x70BA;&#x7C3D;&#x540D;&#x6F14;&#x7B97;&#x6CD5;&#x7684;&#x91D1;&#x9470;&#x3002;</p>
<p>&#x4E0A;&#x9762;&#x7684;&#x6307;&#x4EE4;&#x9664;&#x4E86;&#x5EFA;&#x7ACB; TSIG Secret Key &#x4EE5;&#x5916;&#xFF0C;&#x9084;&#x6703;&#x5C07;&#x9019;&#x500B;&#x8A2D;&#x5B9A;&#x5BEB;&#x5165; BIND9 &#x7684;&#x8A2D;&#x5B9A;&#x6A94;&#x4E2D;&#xFF0C;&#x4E26;&#x91CD;&#x65B0;&#x5553;&#x52D5; BIND9<sup class="footnote-ref"><a href="#fn16" id="fnref16">[16]</a></sup>&#xFF0C;&#x8B93; BIND9 &#x8A8D;&#x8B58;&#x9019;&#x628A;&#x91D1;&#x9470;&#x7684;&#x5B58;&#x5728;&#x3002;</p>
<h2 id="%E8%A8%AD%E5%AE%9A%E6%9B%B4%E6%96%B0%E7%AD%96%E7%95%A5">&#x8A2D;&#x5B9A;&#x66F4;&#x65B0;&#x7B56;&#x7565;</h2>
<p>&#x5149;&#x662F;&#x8B93; BIND9 &#x8A8D;&#x5F97; TSIG &#x91D1;&#x9470;&#x662F;&#x4E0D;&#x5920;&#x7684;&#xFF0C;&#x6211;&#x5011;&#x9084;&#x5FC5;&#x9808;&#x8A2D;&#x5B9A;&#x66F4;&#x65B0;&#x7B56;&#x7565;&#x4EE5;&#x8B93; BIND9 &#x53EF;&#x4EE5;&#x6309;&#x7167;&#x5141;&#x8A31;&#x898F;&#x5247;&#x4F86;&#x653E;&#x884C;&#x8A72;&#x91D1;&#x9470;&#x7684;&#x66F4;&#x65B0;&#x6307;&#x4EE4;&#xFF1A;</p>
<h3 id="%E9%80%8F%E9%81%8E-freeipa-webui">&#x900F;&#x904E; FreeIPA WebUI</h3>
<div>
    <a target="_blank" href="https://blog.davy.tw/content/images/2024/07/-------2024-07-18-223416.png">
    <img src="https://blog.davy.tw/content/images/2024/07/-------2024-07-18-223416.png" title="Network Service &#x2192; DNS Zone &#x2192; Settings" style="max-width: 300px; float: right;" alt="&#x4F7F;&#x7528; cert-manager &#x900F;&#x904E; ACME &#x5F9E; FreeIPA &#x7C3D;&#x767C;&#x6191;&#x8B49;">
    </a>
</div>
<p>&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E; WebUI &#x4F86;&#x9032;&#x884C;&#x66F4;&#x65B0;&#x7B56;&#x7565;&#x7684;&#x8A2D;&#x5B9A;&#xFF0C;&#x5728;&#x767B;&#x5165; WebUI &#x5F8C;&#x9EDE;&#x9078; &quot;Network Service&quot; &#x9078;&#x64C7;&#x8981;&#x7528;&#x4F86;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#x7684; DNS Zone &#x5F8C;&#xFF0C;&#x4F86;&#x5230; Settings &#x4E26;&#x6309;&#x7167;&#x4E0B;&#x65B9;&#x622A;&#x5716;&#x8AAA;&#x660E;&#x8A2D;&#x5B9A;&#xFF1A;&#xFF08;&#x5982;&#x679C;&#x4F60;&#x7684; WebUI &#x4E0D;&#x662F;&#x82F1;&#x6587;&#x7248;&#x672C;&#xFF0C;&#x53EF;&#x53C3;&#x8003;&#x622A;&#x5716;&#x5167;&#x7684;&#x76F8;&#x5C0D;&#x4F4D;&#x7F6E;&#x9032;&#x884C;&#x8A2D;&#x5B9A;&#xFF09;</p>
<p><img src="https://blog.davy.tw/content/images/2024/07/image-1.png" alt="&#x4F7F;&#x7528; cert-manager &#x900F;&#x904E; ACME &#x5F9E; FreeIPA &#x7C3D;&#x767C;&#x6191;&#x8B49;" loading="lazy"></p>
<ul>
<li>&#x5553;&#x7528; &quot;Dynamic update&quot;</li>
<li>&#x5728; &quot;BIND update policy&quot;<sup class="footnote-ref"><a href="#fn17" id="fnref17">[17]</a></sup> &#x4E2D;&#x52A0;&#x5165;&#x898F;&#x5247;&#xFF1A;&#xFF08;&#x622A;&#x5716;&#x4E2D;&#x53CD;&#x767D;&#x5167;&#x5BB9;&#xFF09;
<ul>
<li><code>grant cert-manager-acme wildcard *.k8s.davy.home TXT;</code></li>
<li>&#x8ACB;&#x5C07; <code>cert-manager-acme</code> &#x66FF;&#x63DB;&#x6210;&#x525B;&#x525B;&#x8A2D;&#x5B9A;&#x7684; <code>${TSIG_KEY_NAME}</code> &#x503C;</li>
<li>&#x8ACB;&#x5C07; <code>*.k8s.davy.home</code> &#x66FF;&#x63DB;&#x6210;&#x8B80;&#x8005;&#x60F3;&#x8981;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#x7684; Domain name&#xFF0C;&#x7B46;&#x8005;&#x5728;&#x6B64;&#x60F3;&#x8B93; cert-manager &#x53EF;&#x4EE5;&#x7C3D;&#x767C; <code>k8s.davy.home.</code> &#x4E0B;&#x7684;&#x6240;&#x6709; Subdomain<sup class="footnote-ref"><a href="#fn18" id="fnref18">[18]</a></sup>&#xFF0C;&#x56E0;&#x800C;&#x5982;&#x6B64;&#x8A2D;&#x5B9A;</li>
</ul>
</li>
</ul>
<p>&#x5132;&#x5B58;&#x5F8C;&#x5373;&#x53EF;&#x5B8C;&#x6210;&#x66F4;&#x65B0;&#x7B56;&#x7565;&#x7684;&#x8A2D;&#x5B9A;&#x3002;</p>
<h3 id="%E9%80%8F%E9%81%8E-ipa-cli">&#x900F;&#x904E; <code>ipa</code> CLI</h3>
<p>&#x5982;&#x679C;&#x4E0D;&#x60F3;&#x8981;&#x518D;&#x82B1;&#x6642;&#x9593;&#x767B;&#x5165; WebUI &#x7684;&#x8A71;&#xFF0C;&#x4E5F;&#x6709;&#x900F;&#x904E; <code>ipa</code> &#x6307;&#x4EE4;&#x8A2D;&#x5B9A;&#x7684;&#x65B9;&#x5F0F;&#xFF1A;</p>
<pre><code class="language-txt"># export IPA_DNS_ZONE=davy.home
# ipa dnszone-mod ${IPA_DNS_ZONE} --dynamic-update=True \
    --update-policy=&apos;grant cert-manager-acme wildcard *.k8s.davy.home TXT;&apos;
#
</code></pre>
<p>&#x8ACB;&#x8B80;&#x8005;&#x81EA;&#x884C;&#x4F9D;&#x7167;&#x5BE6;&#x969B;&#x60C5;&#x5F62;&#x66FF;&#x63DB; <code>${IPA_DNS_ZONE}</code> &#x70BA;&#x5C0D;&#x61C9;&#x7684; DNS Zone&#xFF0C;&#x4EE5;&#x53CA;&#x5C07; <code>cert-manager-acme</code> &#x8207; <code>*.k8s.davy.home</code> &#x66FF;&#x63DB;&#x6210;&#x5C0D;&#x61C9;&#x7684;&#x5167;&#x5BB9;&#x3002;</p>
<h1 id="cert-manager-clusterissuerissuer">cert-manager ClusterIssuer/Issuer</h1>
<p>&#x5728; cert-manager &#x9019;&#x5074;&#xFF0C;&#x6211;&#x5011;&#x9700;&#x8981;&#x505A;&#x7684;&#x4E8B;&#x60C5;&#x5C31;&#x76F8;&#x5C0D;&#x7C21;&#x55AE;&#x4E86;&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x5EFA;&#x7ACB;&#x5169;&#x500B;&#x8CC7;&#x6E90; &#x2014;&#x2014; <code>Secret</code> &#x53CA; <code>ClusterIssuer</code>/<code>Issuer</code>&#x3002;</p>
<p>&#x9996;&#x5148;&#x6211;&#x5011;&#x5FC5;&#x9808;&#x5148;&#x6C7A;&#x5B9A;&#x9019;&#x500B; Issuer &#x662F; Cluster-wide &#x7684;&#x9084;&#x662F; Namespace-wide[^namespace] &#x7684;&#xFF0C;&#x5982;&#x679C;&#x4F60;&#x6253;&#x7B97;&#x8B93;&#x6574;&#x500B; Cluster &#x5167;&#x7684;&#x8CC7;&#x6E90;&#x90FD;&#x80FD;&#x4F7F;&#x7528;&#x9019;&#x500B; Issuer &#x7684;&#x8A71;&#x5C31;&#x9078;&#x64C7;&#x5EFA;&#x7ACB; <code>ClusterIssuer</code>&#xFF0C;&#x53CD;&#x4E4B;&#xFF0C;&#x5C31;&#x9078;&#x64C7;&#x5EFA;&#x7ACB; <code>Issuer</code>&#x3002;</p>
<p>&#x672C;&#x6587;&#x5C07;&#x4EE5; <code>ClusterIssuer</code> &#x4F5C;&#x70BA;&#x7BC4;&#x4F8B;&#xFF0C;&#x6700;&#x5927;&#x5DEE;&#x5225;&#x5728;&#x65BC;&#x540C;&#x4E00;&#x500B; <code>Issuer</code> &#x7684;&#x76F8;&#x95DC;&#x8CC7;&#x6E90;&#xFF08;&#x4F8B;&#x5982; <code>Secret</code> &#x7B49;&#xFF09;&#x5FC5;&#x9808;&#x653E;&#x5728;&#x540C;&#x4E00;&#x500B; namespace &#x4E0B;&#xFF1B;&#x800C; <code>ClusterIssuer</code> &#x5247;&#x662F;&#x5C07;&#x76F8;&#x95DC;&#x8CC7;&#x6E90;&#x653E;&#x5728; cert-manager &#x6307;&#x5B9A;&#x7684; namespace&#xFF08;&#x9810;&#x8A2D;&#x8207; cert-manager &#x540C;&#x4E00;&#x500B; namespace<sup class="footnote-ref"><a href="#fn19" id="fnref19">[19]</a></sup>&#xFF09;&#xFF0C;&#x81EA;&#x5DF1;&#x672C;&#x8EAB;&#x4E26;&#x6C92;&#x6709; namespace &#x7684;&#x5C6C;&#x6027;&#x3002;</p>
<h2 id="tsig-secret-key">TSIG Secret Key</h2>
<p>&#x9996;&#x5148;&#xFF0C;&#x6211;&#x5011;&#x5C07;&#x5EFA;&#x7ACB;&#x4E00;&#x500B;&#x5B58;&#x653E; TSIG Secret Key &#x7684; Secret &#x8CC7;&#x6E90;&#xFF1A;</p>
<pre><code class="language-txt">$ kubectl -n cert-manager create secret generic ipa-tsig \
    --from-literal=secret=&quot;${TSIG_SECRET}&quot;
secret/ipa-tsig created
$
</code></pre>
<p>&#x6B64;&#x8655;&#x7684; <code>${TSIG_SECRET}</code> &#x5728;&#x524D;&#x9762;<a href="#tsig-secret-key">&#x3008;FreeIPA DNS &#x2192; TSIG Secret Key&#x3009;</a>&#x4E00;&#x7BC0;&#x4E2D;&#x6709;&#x63D0;&#x5230;&#x904E;&#xFF0C;&#x5982;&#x679C;&#x9084;&#x6C92;&#x6709;&#x53D6;&#x5F97;&#x7684;&#x8B80;&#x8005;&#x8ACB;&#x5148;&#x5F80;&#x524D;&#x7FFB;&#x95B1;&#x3002;</p>
<p>&#x5982;&#x679C;&#x8B80;&#x8005;&#x60F3;&#x5EFA;&#x7ACB;&#x7684;&#x662F; <code>Issuer</code> &#x8CC7;&#x6E90;&#xFF0C;&#x8ACB;&#x5728;&#x9019;&#x4E00;&#x6B65;&#x9A5F;&#x4E2D;&#x5C07; <code>Secret</code> &#x8CC7;&#x6E90;&#x5EFA;&#x7ACB;&#x5728;&#x5C0D;&#x61C9;&#x7684; Namespace &#x4E2D;&#x3002;</p>
<h2 id="%E5%BB%BA%E7%AB%8B-clusterissuer">&#x5EFA;&#x7ACB; ClusterIssuer</h2>
<p>&#x6709;&#x4E86;&#x5B58;&#x653E; TSIG Secret Key &#x7684;&#x8CC7;&#x6E90;&#x5F8C;&#xFF0C;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x4F86;&#x5EFA;&#x7ACB; <code>ClusterIssuer</code> &#x8CC7;&#x6E90;&#x4E86;&#xFF1A;</p>
<pre><code class="language-yaml">---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: ipa
spec:
  acme:
    caBundle: ${IPA_CA_CERT_IN_BASE64}
    privateKeySecretRef:
      name: ipa-acme-account-key
    server: https://${IPA_CA_SERVER}/acme/directory
    solvers:
    - dns01:
        rfc2136:
          nameserver: ${IPA_NS_IP}
          tsigAlgorithm: HMACSHA512
          tsigKeyName: ${TSIG_KEY_NAME}
          tsigSecretSecretRef:
            name: ipa-tsig
            key: secret
      selector:
        dnsZones:
        - ${IPA_DNS_ZONE}
</code></pre>
<p>&#x5176;&#x4E2D;&#x6709;&#x5E7E;&#x500B;&#x503C;&#x9700;&#x8981;&#x8B80;&#x8005;&#x6839;&#x64DA;&#x5BE6;&#x969B;&#x60C5;&#x6CC1;&#x66FF;&#x63DB;&#xFF1A;</p>
<ul>
<li><code>${IPA_CA_CERT_IN_BASE64}</code>
<ul>
<li>FreeIPA &#x7684; CA &#x6191;&#x8B49;&#xFF08;&#x4EE5; base64 &#x7DE8;&#x78BC;&#x7684; PEM &#x683C;&#x5F0F;&#x8868;&#x793A;&#xFF09;</li>
<li>&#x53EF;&#x4EE5;&#x5F9E; FreeIPA &#x4E3B;&#x6A5F;&#x7684; <code>/etc/ipa/ca.crt</code> &#x53D6;&#x5F97;</li>
</ul>
</li>
<li><code>${IPA_CA_SERVER}</code>
<ul>
<li>&#x901A;&#x5E38;&#x6703;&#x662F; <code>ipa-ca.&lt;IPA REALM DOMAIN&gt;</code>&#xFF0C;&#x4EE5;&#x7B46;&#x8005;&#x7684;&#x74B0;&#x5883;&#x4F86;&#x8AAA;&#x5C31;&#x662F; <code>ipa-ca.davy.home</code></li>
</ul>
</li>
<li><code>${IPA_NS_IP}</code>
<ul>
<li>FreeIPA &#x7684; DNS Primary IP&#xFF0C;&#x901A;&#x5E38;&#x5C31;&#x662F; FreeIPA &#x7684; Primary Server IP</li>
</ul>
</li>
<li><code>${TSIG_KEY_NAME}</code>
<ul>
<li>TSIG Secret Key &#x7684;&#x540D;&#x7A31;&#xFF0C;&#x5728;<a href="#tsig-secret-key">&#x3008;FreeIPA DNS &#x2192; TSIG Secret Key&#x3009;</a>&#x4E00;&#x7BC0;&#x6709;&#x63D0;&#x5230;&#xFF0C;&#x4EE5;&#x7B46;&#x8005;&#x7684;&#x6848;&#x4F8B;&#x4F86;&#x8AAA;&#x5C31;&#x662F; <code>cert-manager-acme</code></li>
</ul>
</li>
<li><code>${IPA_DNS_ZONE}</code>
<ul>
<li>&#x4F60;&#x60F3;&#x8981;&#x7C3D;&#x767C;&#x7684; DNS Zone &#x6216; Subdomain&#xFF0C;&#x4EE5;&#x7B46;&#x8005;&#x7684;&#x6848;&#x4F8B;&#x4F86;&#x8AAA;&#x5C31;&#x662F; <code>k8s.davy.home</code></li>
</ul>
</li>
<li><code>ipa-acme-account-key</code>
<ul>
<li>&#x9019;&#x88E1;&#x6703;&#x81EA;&#x52D5;&#x5EFA;&#x7ACB;&#x7528;&#x65BC;&#x5B58;&#x653E; ACME &#x8A3B;&#x518A;&#x8CC7;&#x8A0A;&#x7684; <code>Secret</code>&#xFF0C;&#x8B80;&#x8005;&#x53EF;&#x81EA;&#x7531;&#x66F4;&#x63DB;&#x5176;&#x540D;&#x7A31;</li>
</ul>
</li>
<li><code>server: https://${IPA_CA_SERVER}/acme/directory</code>
<ul>
<li>&#x5982;&#x679C;&#x8B80;&#x8005;&#x60F3;&#x8981;&#x900F;&#x904E; Let&apos;s Encrypt &#x6216;&#x5176;&#x4ED6;&#x4F86;&#x6E90;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#xFF0C;&#x800C;&#x975E;&#x5F9E; FreeIPA &#x7684;&#x8A71;&#xFF0C;&#x8ACB;&#x81EA;&#x884C;&#x8A2D;&#x5B9A;&#x6210;&#x5C0D;&#x61C9;&#x9069;&#x5408;&#x7684; <code>server</code>&#xFF0C;&#x4E26;&#x63D0;&#x4F9B;&#x8A72;&#x7C3D;&#x767C;&#x670D;&#x52D9;&#x8DB3;&#x5920;&#x7684;&#x8CC7;&#x6599;&#xFF0C;&#x8A73;&#x7D30;&#x8ACB;&#x53C3;&#x898B; cert-manager &#x8AAA;&#x660E;&#x6587;&#x4EF6;<a href="https://cert-manager.io/docs/configuration/acme/?ref=blog.davy.tw#creating-a-basic-acme-issuer">&#x3008;ACME &#x2192; Introduction &#x2192; Creating a Basic ACME Issuer&#x3009;</a>&#x4E00;&#x7BC0;</li>
</ul>
</li>
</ul>
<p>&#x5982;&#x679C;&#x8B80;&#x8005;&#x60F3;&#x5EFA;&#x7ACB;&#x7684;&#x662F; <code>Issuer</code> &#x8CC7;&#x6E90;&#xFF0C;&#x8ACB;&#x5728;&#x9019;&#x4E00;&#x6B65;&#x9A5F;&#x4E2D;&#x6539;&#x5EFA;&#x7ACB; <code>Issuer</code> &#x8CC7;&#x6E90;&#xFF0C;&#x4E26;&#x5C07;&#x6B64;&#x5EFA;&#x7ACB;&#x5728;&#x5C0D;&#x61C9;&#x7684; Namespace &#x4E2D;&#x3002;</p>
<p>&#x63A5;&#x4E0B;&#x4F86;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E; <code>kubectl describe</code> &#x4F86;&#x89C0;&#x5BDF; <code>ClusterIssuer</code> &#x8207;&#x6211;&#x5011; FreeIPA ACME &#x670D;&#x52D9;&#x7684;&#x8A3B;&#x518A;&#x60C5;&#x5F62;&#xFF1A;</p>
<pre><code class="language-txt">$ kubectl describe clusterissuer ipa
...
Status:
  Acme:
    Last Private Key Hash:  BbkPF6ZPgulgisJ80ISEIq10JXHIB19M9I2eYOHIFAQ=
    Uri:                    https://ipa.davy.home/acme/rest/acct/Mt72_fSdmemIOK8cj89x6AZhwujqenQ5MyIxqCAnC1Y
  Conditions:
    Last Transition Time:  2024-07-18T15:18:40Z
    Message:               The ACME account was registered with the ACME server
    Observed Generation:   2
    Reason:                ACMEAccountRegistered
    Status:                True
    Type:                  Ready
$
</code></pre>
<p>&#x5982;&#x679C;&#x53EF;&#x4EE5;&#x770B;&#x5230; <code>Reason: ACMEAccountRegistered</code>&#xFF0C;&#x8868;&#x793A;&#x6211;&#x5011;&#x7684; FreeIPA &#x5DF2;&#x7D93;&#x53D7;&#x7406;&#x6211;&#x5011;&#x7684; ACME &#x8A3B;&#x518A;&#x624B;&#x7E8C;&#x4E86;&#x3002;&#x4F46;&#x9019;&#x9084;&#x4E26;&#x4E0D;&#x8868;&#x793A;&#x6211;&#x5011;&#x8A2D;&#x5B9A;&#x7684; TSIG Secret Key &#x5DF2;&#x7D93;&#x6B63;&#x78BA;&#x88AB;&#x9A57;&#x8B49;&#x4E86;&#xFF0C;&#x9019;&#x6703;&#x7B49;&#x5230;&#x6211;&#x5011;&#x771F;&#x7684;&#x9032;&#x884C; DNS-01 &#x9A57;&#x8B49;&#x6642;&#xFF0C;&#x8981;&#x4FEE;&#x6539; TXT RR &#x7684;&#x6642;&#x5019;&#x624D;&#x6703;&#x53BB;&#x9A57;&#x8B49;&#x3002;</p>
<h1 id="tls-ingress">TLS Ingress</h1>
<p>&#x5230;&#x76EE;&#x524D;&#x70BA;&#x6B62;&#xFF0C;&#x6211;&#x5011;&#x5DF2;&#x7D93;&#x5927;&#x81F4;&#x4E0A;&#x5B8C;&#x6210;&#x4E86; FreeIPA &#x53CA; cert-manager &#x5169;&#x5074;&#x7684;&#x4E32;&#x63A5;&#x4E86;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E;&#x65B0;&#x589E;&#x4E00;&#x500B;&#x6E2C;&#x8A66;&#x7528;&#x7684; TLS Ingress &#x4F86;&#x6E2C;&#x8A66;&#x662F;&#x5426;&#x771F;&#x7684;&#x6210;&#x529F;&#x4E86;&#xFF1A;</p>
<pre><code class="language-yaml">---
kind: Namespace
metadata:
  name: cert-manager-acme-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: cert-manager-acme-test
  name: hello-deployment
spec:
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - image: nginx:1.14.2
        imagePullPolicy: IfNotPresent
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  namespace: cert-manager-acme-test
  name: hello-service
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: hello
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: ipa
  namespace: cert-manager-acme-test
  name: hello-ingress
spec:
  rules:
  - host: hello.k8s.davy.home
    http:
      paths:
      - backend:
          service:
            name: hello-service
            port:
              name: http
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - hello.k8s.davy.home
    secretName: hello-tls
</code></pre>
<p>&#x4E0A;&#x9762;&#x7684; yaml &#x6703;&#x90E8;&#x7F72;&#x4E00;&#x7D44; <code>Deployment</code>&#x3001;<code>Service</code> &#x53CA; <code>Ingress</code> &#x5230;&#x4E00;&#x500B;&#x65B0;&#x7684; Namespace <code>cert-manager-acme-test</code> &#x4E2D;&#x3002;</p>
<p>&#x6CE8;&#x610F;&#x6211;&#x5011;&#x5728; <code>Ingress</code> &#x7684;&#x5730;&#x65B9;&#x9664;&#x4E86;&#x8A2D;&#x5B9A; TLS &#x76F8;&#x95DC;&#x7684;&#x5167;&#x5BB9;&#x4EE5;&#x5916;&#xFF0C;&#x9084;&#x591A;&#x4E86;&#x4E00;&#x500B; Annotation <code>cert-manager.io/cluster-issuer</code>&#xFF0C;cert-manager &#x6703;&#x81EA;&#x884C;&#x904E;&#x6FFE;&#x5E36;&#x6709;&#x6B64; Annotation &#x7684; Ingress &#x4E26;&#x4EE5;&#x5176;&#x503C;&#x5C0D;&#x61C9;&#x7684; <code>ClusterIssuer</code> &#x4F86;&#x7C3D;&#x767C;&#x6191;&#x8B49;<sup class="footnote-ref"><a href="#fn20" id="fnref20">[20]</a></sup>&#x3002;</p>
<p>&#x5982;&#x679C;&#x60F3;&#x4F7F;&#x7528; <code>Issuer</code> &#x7684;&#x8A71;&#xFF0C;&#x6B64;&#x8655;&#x63DB;&#x6210; <code>cert-manager.io/issuer</code> &#x5373;&#x53EF;&#x3002;</p>
<p>&#x4E0A;&#x65B9;&#x7684; <code>Ingress</code> &#x5728;&#x8A2D;&#x5B9A; TLS &#x6642;&#x4E00;&#x4F75;&#x8A2D;&#x5B9A;&#x4E86;&#x4E00;&#x500B; <code>secretName</code>&#xFF0C;&#x6B64;&#x70BA;&#x5B58;&#x653E; TLS &#x6191;&#x8B49;&#x53CA;&#x91D1;&#x9470;&#x7528;&#x7684; <code>Secret</code> &#x8CC7;&#x6E90;&#x7684;&#x540D;&#x7A31;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x5B58;&#x5728;&#x7684;&#x8A71;&#x6703;&#x81EA;&#x52D5;&#x5EFA;&#x7ACB;&#x3002;&#x800C;&#x6211;&#x5011;&#x4EA6;&#x53EF;&#x4EE5;&#x900F;&#x904E;&#x89C0;&#x5BDF;&#x9019;&#x500B; <code>Secret</code> &#x53CA;&#x5176;&#x5C0D;&#x61C9;&#x7684; <code>cert-manager.io/v1/CertificateRequest</code> &#x8CC7;&#x6E90;&#x4F86;&#x770B;&#x5230;&#x6191;&#x8B49;&#x7C3D;&#x767C;&#x7684;&#x72C0;&#x614B;&#x5982;&#x4F55;&#xFF1A;</p>
<pre><code class="language-txt">$ kubectl -n cert-manager-acme-test get secret hello-tls -o yaml
apiVersion: v1
data:
  tls.crt: ...
  tls.key: ...
kind: Secret
metadata:
  annotations:
    cert-manager.io/alt-names: hello.k8s.davy.home
    cert-manager.io/certificate-name: hello-tls
    cert-manager.io/common-name: hello.k8s.davy.home
    cert-manager.io/ip-sans: &quot;&quot;
    cert-manager.io/issuer-group: cert-manager.io
    cert-manager.io/issuer-kind: ClusterIssuer
    cert-manager.io/issuer-name: ipa
    cert-manager.io/uri-sans: &quot;&quot;
  labels:
    controller.cert-manager.io/fao: &quot;true&quot;
  name: hello-tls
  namespace: cert-manager-acme-test
type: kubernetes.io/tls
$ kubectl -n cert-manager-acme-test get CertificateRequest \
  -o custom-columns=&quot;NAME:.metadata.name,Secret:.metadata.annotations.cert-manager\.io/certificate-name,Issuer:.spec.issuerRef.name,Issued:.status.conditions[?(@.type==&apos;Ready&apos;)].status&quot;
NAME          Secret      Issuer   Issued
hello-tls-1   hello-tls   ipa      True
$ kubectl -n cert-manager-acme-test get CertificateRequest hello-tls-1 -o yaml
apiVersion: cert-manager.io/v1
kind: CertificateRequest
metadata:
  annotations:
    cert-manager.io/certificate-name: hello-tls
    cert-manager.io/certificate-revision: &quot;1&quot;
    cert-manager.io/private-key-secret-name: hello-tls-7nrlt
  name: hello-tls-1
  namespace: cert-manager-acme-test
  ownerReferences:
  - apiVersion: cert-manager.io/v1
    blockOwnerDeletion: true
    controller: true
    kind: Certificate
    name: hello-tls
spec:
  issuerRef:
    group: cert-manager.io
    kind: ClusterIssuer
    name: ipa
  request: ...
status:
  certificate: ...
  conditions:
  - lastTransitionTime: &quot;2024-07-18T14:58:21Z&quot;
    message: Certificate request has been approved by cert-manager.io
    reason: cert-manager.io
    status: &quot;True&quot;
    type: Approved
  - lastTransitionTime: &quot;2024-07-18T15:19:48Z&quot;
    message: Certificate fetched from issuer successfully
    reason: Issued
    status: &quot;True&quot;
    type: Ready
$
</code></pre>
<p>&#x5F9E; <code>Secret</code> &#x53CA;&#x5C0D;&#x61C9;&#x7684; <code>CertificateRequest</code> &#x4E2D;&#x53EF;&#x4EE5;&#x770B;&#x51FA;&#x4F86;&#xFF0C;cert-manager &#x5DF2;&#x7D93;&#x5E6B;&#x6211;&#x5011;&#x5B8C;&#x6210;&#x4E86;&#x4E00;&#x689D;&#x9F8D; &#x2014;&#x2014; &#x5F9E;&#x8A2D;&#x5B9A; TLS Ingress &#x5230;&#x8A2D;&#x5B9A; TXT RR &#x5230;&#x901A;&#x904E; DNS-01 &#x9A57;&#x8B49;&#x518D;&#x56DE;&#x5230;&#x8A2D;&#x5B9A; Ingress &#x6191;&#x8B49;&#x3002;</p>
<p>&#x6211;&#x5011;&#x4E5F;&#x53EF;&#x4EE5;&#x6253;&#x958B;&#x5C0D;&#x61C9;&#x7684; Ingress URL &#x4F86;&#x770B;&#x5230;&#x7D50;&#x679C;&#xFF1A;</p>
<table><tbody><tr><td>
<p><img src="https://blog.davy.tw/content/images/2024/07/-------2024-07-19-001539.png" alt="&#x4F7F;&#x7528; cert-manager &#x900F;&#x904E; ACME &#x5F9E; FreeIPA &#x7C3D;&#x767C;&#x6191;&#x8B49;" loading="lazy"></p>
</td><td>
<p><img src="https://blog.davy.tw/content/images/2024/07/-------2024-07-19-001628.png" alt="&#x4F7F;&#x7528; cert-manager &#x900F;&#x904E; ACME &#x5F9E; FreeIPA &#x7C3D;&#x767C;&#x6191;&#x8B49;" loading="lazy"></p>
</td></tr></tbody></table>
<h1 id="%E5%BE%8C%E8%A8%98">&#x5F8C;&#x8A18;</h1>
<p>&#x539F;&#x672C;&#x4EE5;&#x70BA;&#x53EF;&#x4EE5;&#x5728;&#x5169;&#x5929;&#x5167;&#x9023;&#x7E8C;&#x7522;&#x51FA;&#x7684;&#x9019;&#x7BC7;&#x6587;&#x7AE0;&#x7D50;&#x679C;&#x53C8;&#x62D6;&#x4E86;&#x5169;&#x5929;&#x624D;&#x7D42;&#x65BC;&#x5BEB;&#x5B8C;&#xFF0C;&#x6E96;&#x5099;&#x74B0;&#x5883;&#x660E;&#x660E;&#x53EA;&#x82B1;&#x4E86;&#x4E00;&#x500B;&#x665A;&#x4E0A;&#xFF0C;&#x7D50;&#x679C;&#x5927;&#x90E8;&#x5206;&#x7684;&#x6642;&#x9593;&#x90FD;&#x82B1;&#x5728;&#x627E;&#x5C0D;&#x61C9;&#x7684; Reference&#x3002; Orz</p>
<p>&#x7E3D;&#x4E4B;&#xFF0C;&#x9019;&#x500B;&#x6280;&#x5DE7;&#x9664;&#x4E86;&#x8B93; FreeIPA &#x7C3D;&#x767C;&#x6191;&#x8B49;&#x5916;&#xFF0C;&#x53EA;&#x8981;&#x662F;&#x900F;&#x904E; FreeIPA &#x6216;&#x751A;&#x81F3;&#x7D14;&#x7CB9;&#x5730;&#x7528; BIND9 &#x7BA1;&#x7406; DNS &#x7684;&#x4EBA;&#x90FD;&#x80FD;&#x4F7F;&#x7528;&#x9019;&#x500B;&#x65B9;&#x5F0F;&#x81EA;&#x52D5;&#x5316;&#x8A2D;&#x5B9A; TXT RR &#x4F86;&#x81EA;&#x52D5;&#x5B8C;&#x6210; DNS-01 &#x9A57;&#x8B49;&#x3002;</p>
<p>&#x6216;&#x662F;&#x4E5F;&#x53EF;&#x4EE5;&#x5EF6;&#x4F38;&#x51FA;&#x5176;&#x4ED6;&#x7684;&#x7528;&#x6CD5;&#xFF0C;&#x5176;&#x5BE6;&#x4E26;&#x4E0D;&#x9650;&#x65BC; ACME &#x7684;&#x5834;&#x666F;&#x800C;&#x5DF2;&#xFF0C;&#x5982;&#x679C;&#x80FD;&#x5920;&#x7406;&#x89E3;&#x80CC;&#x5F8C;&#x7684;&#x8A2D;&#x5B9A;&#x7684;&#x610F;&#x7FA9;&#x7684;&#x8A71;&#x5C31;&#x6703;&#x6709;&#x66F4;&#x591A;&#x6709;&#x8DA3;&#x7684;&#x61C9;&#x7528;&#x53EF;&#x4EE5;&#x767C;&#x6398;&#x3002; &#xFF1A;&#xFF09;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>Kubernetes &#x662F;&#x7528;&#x65BC;&#x81EA;&#x52D5;&#x90E8;&#x7F72;&#x3001;&#x64F4;&#x5C55;&#x548C;&#x7BA1;&#x7406;&#x300C;&#x5BB9;&#x5668;&#x5316;&#xFF08;containerized&#xFF09;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x300D;&#x7684;&#x958B;&#x6E90;&#x7CFB;&#x7D71;&#xFF0C;&#x8A73;&#x898B;&#x5176;<a href="https://kubernetes.io/?ref=blog.davy.tw">&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>&#x6B64;&#x8655;&#x6307; Kubernetes &#x4E2D;&#x7684; <code>networking.k8s.io/v1/Ingress</code> &#x8CC7;&#x6E90;&#xFF0C;&#x7528;&#x65BC;&#x5F9E; Cluster &#x4E2D;&#x66B4;&#x9732; HTTP/HTTPS &#x670D;&#x52D9;&#x81F3;&#x5916;&#x754C;&#xFF0C;&#x5176;&#x8A73;&#x7D30;&#x6982;&#x5FF5;&#x8ACB;&#x898B; Kubernetes &#x6587;&#x4EF6;<a href="https://kubernetes.io/docs/concepts/services-networking/ingress/?ref=blog.davy.tw">&#x300A;Ingress&#x300B;</a>&#x4E00;&#x7AE0;&#x4E2D;&#x7684;&#x89E3;&#x91CB; <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>cert-manager &#x662F;&#x7528;&#x65BC; Kubernetes &#x4E2D;&#x7684; X.509 &#x6191;&#x8B49;&#x7BA1;&#x7406;&#x5668;&#xFF0C;&#x8A73;&#x898B;&#x5176;&#x5B98;&#x65B9;&#x7DB2;&#x7AD9; <a href="https://cert-manager.io/?ref=blog.davy.tw">https://cert-manager.io/</a> <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>&quot;Automatic Certificate Management Environment&quot;&#xFF0C;&#x81EA;&#x52D5;&#x5316;&#x6191;&#x8B49;&#x7BA1;&#x7406;&#x74B0;&#x5883;&#xFF0C;&#x5B9A;&#x7FA9;&#x65BC; <a href="https://datatracker.ietf.org/doc/html/rfc8555/?ref=blog.davy.tw">RFC-8555</a>&#xFF0C;&#x6216;&#x53EF;&#x53C3;&#x8003; Let&apos;s Encrypt &#x63D0;&#x4F9B;&#x7684;<a href="https://letsencrypt.org/docs/challenge-types/?ref=blog.davy.tw">&#x89E3;&#x91CB;</a> <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p>Let&apos;s Encrypt &#x662F;&#x7531; <a href="https://www.abetterinternet.org/?ref=blog.davy.tw">ISRG (Internet Security Research Group)</a> &#x63D0;&#x4F9B;&#x7684;&#x975E;&#x71DF;&#x5229; CA &#x6191;&#x8B49;&#x6A5F;&#x69CB;&#xFF0C;&#x5176;&#x900F;&#x904E; ACME &#x8B49;&#x660E;&#x7DB2;&#x57DF;&#x6240;&#x6709;&#x6B0A;&#x5F8C;&#x53EF;&#x514D;&#x8CBB;&#x63D0;&#x4F9B;&#x5176;&#x6240;&#x6709;&#x8005;&#x77ED;&#x671F; TLS &#x6191;&#x8B49;&#xFF0C;&#x8A73;&#x898B;&#x5176;&#x5B98;&#x7DB2; <a href="https://letsencrypt.org/?ref=blog.davy.tw">https://letsencrypt.org/</a> <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p>HTTP-01 &#x70BA; ACME &#x5B9A;&#x7FA9;&#x7684;&#x9A57;&#x8B49;&#x65B9;&#x5F0F;&#x4E4B;&#x4E00;&#xFF0C;&#x900F;&#x904E;&#x6240;&#x6709;&#x8005;&#x5728;&#x6307;&#x5B9A;&#x4F4D;&#x7F6E;&#xFF08;<code>https://&lt;DOMAIN&gt;/.well-known/acme-challenge/&lt;TOKEN&gt;</code>&#xFF09;&#x653E;&#x7F6E;&#x6307;&#x5B9A;&#x5167;&#x5BB9;&#x7684;&#x65B9;&#x5F0F;&#x9A57;&#x8B49;&#x5176;&#x7DB2;&#x57DF;&#x6240;&#x6709;&#x6B0A; <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn7" class="footnote-item"><p>DNS-01 &#x70BA; ACME &#x5B9A;&#x7FA9;&#x7684;&#x9A57;&#x8B49;&#x65B9;&#x5F0F;&#x4E4B;&#x4E00;&#xFF0C;&#x900F;&#x904E;&#x6240;&#x6709;&#x8005;&#x8A2D;&#x5B9A;&#x6307;&#x5B9A; TXT RR &#xFF08;<code>_acme-challenge.&lt;DOMAIN&gt;</code>&#xFF09;&#x4F86;&#x9A57;&#x8B49;&#x5176;&#x7DB2;&#x57DF;&#x6240;&#x6709;&#x6B0A; <a href="#fnref7" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn8" class="footnote-item"><p>FreeIPA &#x662F;&#x514D;&#x8CBB;&#x7684;&#x958B;&#x6E90;&#x8EAB;&#x4EFD;&#x7BA1;&#x7406;&#x7CFB;&#x7D71;&#xFF0C;IPA &#x5206;&#x5225;&#x4EE3;&#x8868; Identity&#x3001;Policy&#x3001;Audit&#xFF0C;&#x540C;&#x6642;&#x4E5F;&#x662F; Red Hat Identity Manager &#x7684;&#x4E0A;&#x6E38;&#x958B;&#x6E90;&#x5C08;&#x6848;&#xFF0C;&#x8A73;&#x898B;&#x5176;<a href="https://www.freeipa.org/?ref=blog.davy.tw">&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;</a> <a href="#fnref8" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn9" class="footnote-item"><p>BIND9 &#x662F;&#x73FE;&#x4ECA;&#x7DB2;&#x969B;&#x7DB2;&#x8DEF;&#x4E0A;&#x5E38;&#x898B;&#x7684; DNS &#x4F3A;&#x670D;&#x5668;&#x8EDF;&#x9AD4;&#xFF0C;&#x76EE;&#x524D;&#x7531;&#x7DB2;&#x969B;&#x7DB2;&#x8DEF;&#x7CFB;&#x7D71;&#x5354;&#x6703;(ISC, Internet Systems Consortium)&#x8CA0;&#x8CAC;&#x958B;&#x767C;&#x8207;&#x7DAD;&#x8B77;&#x3002;&#x8A73;&#x898B;&#x7DAD;&#x57FA;&#x767E;&#x79D1;<a href="https://en.wikipedia.org/wiki/BIND?ref=blog.davy.tw">&#x300A;BIND&#x300B;</a>&#x689D;&#x76EE;&#xFF0C;&#x6216;&#x5176;<a href="https://www.isc.org/bind/?ref=blog.davy.tw">&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;</a> <a href="#fnref9" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn10" class="footnote-item"><p>&#x95DC;&#x65BC;&#x5728; cert-mananger &#x4E2D;&#x8A2D;&#x5B9A; RFC-2136 &#x7684;&#x8A73;&#x7D30;&#x65B9;&#x5F0F;&#x53CA;&#x8AAA;&#x660E;&#x8ACB;&#x53C3;&#x95B1;&#x4F7F;&#x7528;&#x624B;&#x518A;<a href="https://cert-manager.io/docs/configuration/acme/dns01/rfc2136/?ref=blog.davy.tw">&#x3008;DNS-01 / RFC-2136&#x3009;&#x4E00;&#x7BC0;</a> <a href="#fnref10" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn11" class="footnote-item"><p>&quot;Dynamic Updates in the Domain Name System (DNS UPDATE)&quot;&#xFF0C;&#x65E8;&#x5728;&#x4F7F;&#x5F97; DNS &#x53EF;&#x4EE5;&#x5728;&#x7DDA;&#x4E0A;&#x52D5;&#x614B;&#x66F4;&#x65B0;&#x8A18;&#x9304;&#xFF0C;&#x8A73;&#x898B; <a href="https://datatracker.ietf.org/doc/html/rfc2136?ref=blog.davy.tw">RFC-2136</a> &#x5167;&#x5BB9; <a href="#fnref11" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn12" class="footnote-item"><p>Resource Record&#xFF0C;<a href="https://datatracker.ietf.org/doc/html/rfc1034?ref=blog.davy.tw#section-3.6">RFC-1034 3.6</a> <a href="#fnref12" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn13" class="footnote-item"><p>Transaction Signature&#xFF0C;&#x7531; RFC-2845 &#x5B9A;&#x7FA9;&#x7684; RR Type&#xFF0C;&#x8A73;&#x898B; <a href="https://datatracker.ietf.org/doc/html/rfc2845?ref=blog.davy.tw">RFC-2845</a> &#x6216;&#x7DAD;&#x57FA;&#x767E;&#x79D1;&#x4E0A;&#x7684;<a href="https://en.wikipedia.org/wiki/TSIG?ref=blog.davy.tw">&#x300A;TSIG&#x300B;</a>&#x689D;&#x76EE; <a href="#fnref13" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn14" class="footnote-item"><p>&#x6B64;&#x8655;&#x7684;&#x300C;&#x7C3D;&#x540D;&#x300D;&#x6307;&#x7684;&#x662F; MAC (Message Authentication Code)&#xFF0C;&#x7528;&#x65BC;&#x8A8D;&#x8B49;&#x53CA;&#x78BA;&#x8A8D;&#x8CC7;&#x6599;&#x5B8C;&#x6574;&#x6027;&#xFF0C;&#x6709;&#x95DC; MAC &#x7684;&#x8AAA;&#x660E;&#x8ACB;&#x53C3;&#x95B1;&#x7DAD;&#x57FA;&#x767E;&#x79D1;<a href="https://en.wikipedia.org/wiki/Message_authentication_code?ref=blog.davy.tw">&#x300A;Message Authentication Code&#x300B;</a>&#x689D;&#x76EE; <a href="#fnref14" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn15" class="footnote-item"><p>&#x5728; RFC-2845 &#x4E2D;&#x50C5;&#x5B9A;&#x7FA9; TSIG &#x53EF;&#x63A1;&#x7528; <code>HMAC-MD5</code> &#x4F5C;&#x70BA;&#x7C3D;&#x540D;&#x6F14;&#x7B97;&#x6CD5;&#xFF0C;&#x4F46; MD5 &#x5728; 2024 &#x7684;&#x73FE;&#x5728;&#x5DF2;&#x4E0D;&#x5920;&#x5B89;&#x5168;&#xFF0C;&#x56E0;&#x6B64;&#x6211;&#x5011;&#x5728;&#x6B64;&#x9078;&#x64C7;&#x4F7F;&#x7528; RFC-4635 &#x64F4;&#x5145;&#x652F;&#x63F4;&#x7684; HMAC-SHA512 &#x6F14;&#x7B97;&#x6CD5;&#x3002;&#x95DC;&#x65BC; HMAC-SHA &#x7CFB;&#x5217;&#x6F14;&#x7B97;&#x6CD5;&#x7684;&#x5B9A;&#x7FA9;&#x8ACB;&#x53C3;&#x95B1; <a href="https://datatracker.ietf.org/doc/html/rfc4634?ref=blog.davy.tw">RFC-4634</a>&#xFF1B;SHA &#x7CFB;&#x5217;&#x6F14;&#x7B97;&#x6CD5;&#x7684;&#x5B9A;&#x7FA9;&#x8ACB;&#x53C3;&#x95B1; <a href="https://csrc.nist.gov/pubs/fips/180-4/upd1/final?ref=blog.davy.tw">FIPS180-4</a> <a href="#fnref15" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn16" class="footnote-item"><p>&#x4F9D;&#x64DA;&#x5BE6;&#x969B;&#x60C5;&#x6CC1;&#x7684;&#x4E0D;&#x540C;&#xFF0C;FreeIPA &#x5553;&#x7528;&#x7684; BIND9 &#x53EF;&#x80FD;&#x662F; <code>named.server</code> &#x6216; <code>named-pkcs11.server</code>&#xFF0C;&#x9019;&#x88E1;&#x7B46;&#x8005;&#x5077;&#x61F6;&#x5C07;&#x5169;&#x500B;&#x90FD;&#x91CD;&#x5553;&#x8A66;&#x8A66;&#x770B;&#xFF0C;&#x8B80;&#x8005;&#x53EF;&#x4EE5;&#x8996;&#x60C5;&#x6CC1;&#x81EA;&#x884C;&#x8ABF;&#x6574; <a href="#fnref16" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn17" class="footnote-item"><p>BIND9 &#x63D0;&#x4F9B;&#x4E86;&#x8A31;&#x591A;&#x66F4;&#x65B0;&#x7B56;&#x7565;&#x7684;&#x8A2D;&#x5B9A;&#x65B9;&#x5F0F;&#xFF0C;&#x5176;&#x4ED6;&#x898F;&#x5247;&#x5BEB;&#x6CD5;&#x53EF;&#x53C3;&#x898B;&#x7B46;&#x8005;&#x5E38;&#x53C3;&#x8003;&#x7684; ZyTrax &#x7DB2;&#x7AD9;&#x4E2D;&#x95DC;&#x65BC; <a href="https://www.zytrax.com/books/dns/ch7/xfer.html?ref=blog.davy.tw#update-policy">update-policy</a> &#x7684;&#x8AAA;&#x660E; <a href="#fnref17" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn18" class="footnote-item"><p>Subdomain &#x2014;&#x2014; &#x5B50;&#x57DF;&#x540D;&#xFF0C;&#x70BA;&#x6307;&#x5B9A;&#x57DF;&#x540D;&#x518D;&#x591A;&#x4E00;&#x5C64;&#x7684;&#x57DF;&#x540D;&#xFF0C;&#x8A73;&#x898B;&#x7DAD;&#x57FA;&#x767E;&#x79D1;<a href="https://en.wikipedia.org/wiki/Subdomain?ref=blog.davy.tw">&#x300A;Subdomain&#x300B;</a>&#x689D;&#x76EE; <a href="#fnref18" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn19" class="footnote-item"><p>&#x95DC;&#x65BC; ClusterIssuer/Issuer &#x76F8;&#x95DC;&#x7684; Secret &#x9700;&#x653E;&#x7F6E;&#x65BC;&#x4F55; Namespace &#x53EF;&#x53C3;&#x898B;<a href="https://github.com/cert-manager/cert-manager/blob/v1.15.1/pkg/apis/meta/v1/types.go?ref=blog.davy.tw#L39">&#x539F;&#x59CB;&#x78BC;&#x4E2D;&#x7684;&#x8AAA;&#x660E;</a>&#xFF0C;&#x95DC;&#x65BC;&#x5982;&#x4F55;&#x8A2D;&#x5B9A; Cluster resource namespace&#xFF0C;&#x5982;&#x679C;&#x662F;&#x4F7F;&#x7528; Helm &#x90E8;&#x7F72; cert-mananger &#x7684;&#x8B80;&#x8005;&#x53EF;&#x4EE5;&#x53C3;&#x95B1; <a href="https://artifacthub.io/packages/helm/cert-manager/cert-manager?ref=blog.davy.tw#clusterresourcenamespace-~-string"><code>clusterResourceNamespace</code></a> &#x7684;&#x8A2D;&#x5B9A;&#x8AAA;&#x660E; <a href="#fnref19" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn20" class="footnote-item"><p>cert-manager &#x6703;&#x900F;&#x904E; webhook &#x4F86;&#x5C0D; <code>Ingress</code> &#x505A;&#x6574;&#x5408;&#xFF0C;&#x8A73;&#x898B; cert-mananger &#x6587;&#x4EF6;&#x4E2D;<a href="https://cert-manager.io/docs/usage/ingress/?ref=blog.davy.tw">&#x3008;Requesting Certificates &#x2192; Ingress&#x3009;</a>&#x4E00;&#x7BC0; <a href="#fnref20" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[掛載 WSL2 的目錄到 Podman 中]]></title><description><![CDATA[Podman Desktop 預設提供與 Windows Host 的整合，與 WSL2 的整合卻要自己動手來。但就算按照步驟將 WSL2 與 Podman 整合起來之後，你還會發現一些小問題 —— 例如掛載不到 WSL2 中的目錄……]]></description><link>https://blog.davy.tw/posts/mount-other-wsl2-distro-into-podman-container/</link><guid isPermaLink="false">6697c3315cd77700015115d1</guid><category><![CDATA[WSL]]></category><category><![CDATA[WSL2]]></category><category><![CDATA[Podman]]></category><category><![CDATA[Container]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Wed, 17 Jul 2024 16:11:25 GMT</pubDate><media:content url="https://blog.davy.tw/content/images/2024/07/---2-2.png" medium="image"/><content:encoded><![CDATA[<h1 id="tldr">TL;DR</h1>
<pre><code class="language-bash">cat &lt;&lt;-EOF | sudo tee /etc/systemd/system/mnt-wsl-instances-${WSL_DISTRO_NAME}.mount
[Unit]
Description=WSL Instances

[Mount]
What=/
Where=/mnt/wsl/instances/${WSL_DISTRO_NAME}
Type=none
Options=defaults,bind,X-mount.mkdir

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now mnt-wsl-instances-${WSL_DISTRO_NAME}.mount
</code></pre>
<pre><code class="language-bash">podman-remote run \
  -v /mnt/wsl/instances/${WSL_DISTRO_NAME}/`pwd`:/app \
  docker.io/library/busybox ls /app
</code></pre>
<h1 id="%E5%89%8D%E6%83%85%E6%8F%90%E8%A6%81">&#x524D;&#x60C5;&#x63D0;&#x8981;</h1>
<img src="https://blog.davy.tw/content/images/2024/07/---2-2.png" alt="&#x639B;&#x8F09; WSL2 &#x7684;&#x76EE;&#x9304;&#x5230; Podman &#x4E2D;"><p>Podman<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> &#x662F;&#x4E00;&#x500B;&#x7531; Redhat<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x4E3B;&#x63A8;&#x7684; Container<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> &#x5DE5;&#x5177;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x7528;&#x904E;&#x5BB9;&#x5668;&#x7684;&#x8B80;&#x8005;&#x5011;&#x61C9;&#x8A72;&#x5C0D;&#x65BC;&#x8207;&#x5176;&#x985E;&#x4F3C;&#x7684; Docker<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup> &#x4E0D;&#x964C;&#x751F;&#xFF0C;Podman &#x5C31;&#x662F;&#x4E00;&#x500B;&#x9019;&#x6A23;&#x7684;&#x5BB9;&#x5668;&#x7BA1;&#x7406;&#x5DE5;&#x5177;&#x3002;</p>
<p>&#x8207; Docker &#x4E0D;&#x540C;&#x7684;&#x662F;&#xFF0C;Podman &#x53E6;&#x5916;&#x5F15;&#x5165;&#x4E86; Pod<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup> &#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x4EE5;&#x53CA;&#x5177;&#x6709;&#x9810;&#x8A2D;&#x652F;&#x63F4; rootless &#x53CA;&#x53BB; daemon &#x5316;&#x7B49;&#x7279;&#x8272;&#x3002;</p>
<h2 id="podman-desktop">Podman Desktop</h2>
<p>Podman &#x5718;&#x968A;&#x5728;&#x5404;&#x5E73;&#x81FA;&#x4E0A;&#x63A8;&#x51FA;&#x4E86;&#x684C;&#x9762;&#x7BA1;&#x7406;&#x5DE5;&#x5177; &#x2014;&#x2014; Podman Desktop<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>&#xFF0C;&#x985E;&#x4F3C;&#x65BC; Docker Desktop &#x63D0;&#x4F9B;&#x8996;&#x89BA;&#x5316;&#x7684;&#x7BA1;&#x7406;&#x529F;&#x80FD;&#x5916;&#xFF0C;&#x4E5F;&#x80FD;&#x5354;&#x52A9;&#x4F7F;&#x7528;&#x8005;&#x5B89;&#x88DD; Podman &#x81F3;&#x7CFB;&#x7D71;&#x4E2D;&#x4E26;&#x63D0;&#x4F9B;&#x5404;&#x7A2E;&#x8A2D;&#x5B9A;&#x53CA;&#x64F4;&#x5145;&#x529F;&#x80FD;&#x3002;</p>
<p>&#x6709;&#x8208;&#x8DA3;&#x5F9E; Docker &#x8DF3;&#x8239;&#x7684;&#x8B80;&#x8005;&#x53EF;&#x4EE5;&#x53C3;&#x8003; Podman Desktop &#x63D0;&#x4F9B;&#x7684;&#x8DF3;&#x8239;&#x6307;&#x5357;&#xFF1A; <a href="https://podman-desktop.io/docs/migrating-from-docker?ref=blog.davy.tw">https://podman-desktop.io/docs/migrating-from-docker</a></p>
<h2 id="windows-%E4%B8%8B%E7%9A%84-podman">Windows &#x4E0B;&#x7684; Podman</h2>
<p>&#x5728; Windows &#x4E0A;&#xFF0C;Podman &#x6703;&#x5728; Windows &#x4E2D;&#x5B89;&#x88DD; <code>podman.exe</code>&#xFF0C;&#x5354;&#x52A9;&#x4F60;&#x5728; Host &#x7684; Command line &#x4E2D;&#x8F15;&#x9B06;&#x5B58;&#x53D6; Podman&#xFF0C;&#x4F8B;&#x5982;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x6253;&#x958B;&#x4E00;&#x500B; PowerShell&#xFF08;&#x6216; CMD&#xFF09;&#xFF0C;&#x57F7;&#x884C; <code>podman version</code>&#xFF0C;&#x5373;&#x53EF;&#x770B;&#x5230;&#x985E;&#x4F3C;&#x4E0B;&#x65B9;&#x622A;&#x5716;&#x7684;&#x7D50;&#x679C;&#xFF1A;</p>
<p><img src="https://blog.davy.tw/content/images/2024/07/---2.png" alt="&#x639B;&#x8F09; WSL2 &#x7684;&#x76EE;&#x9304;&#x5230; Podman &#x4E2D;" loading="lazy"></p>
<p>&#x5927;&#x5BB6;&#x53EF;&#x4EE5;&#x6CE8;&#x610F;&#x5230;&#xFF0C;&#x96D6;&#x7136;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x5728; Windows &#x4E0B;&#x9762;&#x57F7;&#x884C; Podman &#x6307;&#x4EE4;&#xFF0C;&#x4F46;&#x5BE6;&#x969B;&#x4E0A;&#x7684; Podman Engine &#x537B;&#x662F;&#x57F7;&#x884C;&#x5728; Linux &#x4E0A;&#x7684;&#xFF0C;&#x9019;&#x662F;&#x56E0;&#x70BA; Podman &#x76EE;&#x524D;&#x53EA;&#x80FD;&#x7BA1;&#x7406; Linux Container&#xFF0C;&#x56E0;&#x6B64; Podman &#x6C7A;&#x5B9A;&#x5C07; Podman Engine &#x8DD1;&#x5728; WSL2 &#x4E2D;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x5B89;&#x88DD; Windows Terminal &#x7684;&#x8A71;&#xFF0C;&#x53EF;&#x4EE5;&#x5F9E;&#x81EA;&#x52D5;&#x7522;&#x751F;&#x7684;&#x4E0B;&#x62C9;&#x9078;&#x55AE;&#x4E2D;&#x767C;&#x73FE;&#x4E00;&#x500B;&#x65B0;&#x7684; WSL2 &#x7684; Distro&#x3002;</p>
<p><img src="https://blog.davy.tw/content/images/2024/07/---2-1.png" alt="&#x639B;&#x8F09; WSL2 &#x7684;&#x76EE;&#x9304;&#x5230; Podman &#x4E2D;" loading="lazy"></p>
<p>&#x4E26;&#x4E14; Podman &#x6703;&#x5E6B;&#x4F60;&#x505A;&#x597D;&#x8207; Windows Host &#x7684;&#x6574;&#x5408;&#xFF0C;&#x4F8B;&#x5982;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x639B;&#x8F09; Windows &#x7684;&#x76EE;&#x9304;&#x6216;&#x6A94;&#x6848;&#x9032;&#x5BB9;&#x5668;&#x4E2D;&#xFF0C;&#x4F8B;&#x5982;&#xFF1A;</p>
<pre><code class="language-txt">PS C:\Users\Davy\podman-test&gt; echo &quot;Hi Podman from Windows&quot; &gt; hello.txt
PS C:\Users\Davy\podman-test&gt; podman run --rm -v .\hello.txt:/hello.txt docker.io/library/busybox cat /hello.txt
Trying to pull docker.io/library/busybox:latest...
Getting image source signatures
Copying blob sha256:ec562eabd705d25bfea8c8d79e4610775e375524af00552fe871d3338261563c
Copying config sha256:65ad0d468eb1c558bf7f4e64e790f586e9eda649ee9f130cd0e835b292bbc5ac
Writing manifest to image destination
&#xFFFD;&#xFFFD;Hi Podman from Windows
PS C:\Users\Davy\podman-test&gt;
</code></pre>
<p>&#xFF08;&#x8ACB;&#x5FFD;&#x7565;&#x90A3;&#x5169;&#x500B;&#x770B;&#x4E0D;&#x898B;&#x7684; BOM &#x7B26;&#x865F;&#x2026;&#x2026;&#xFF09;</p>
<p>&#x4E5F;&#x5C31;&#x662F;&#x8AAA;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x96A8;&#x610F;&#x5730;&#x7DE8;&#x5BEB; PowerShell &#x8173;&#x672C;&#xFF08;&#x6216; CMD &#x6279;&#x6B21;&#x6A94;&#xFF09;&#x4F86;&#x64CD;&#x4F5C; Podman&#xFF01;&#x1F60F;</p>
<h2 id="wsl2-%E4%B8%8B%E7%9A%84-podman">WSL2 &#x4E0B;&#x7684; Podman</h2>
<p>&#x90A3;&#x9EBC;&#xFF0C;&#x901A;&#x5E38;&#x6703;&#x4F7F;&#x7528; Podman &#x7684;&#x8A71;&#xFF0C;&#x61C9;&#x8A72;&#x6703;&#x5C0D; WSL2<sup class="footnote-ref"><a href="#fn7" id="fnref7">[7]</a></sup> &#x4E5F;&#x4E0D;&#x964C;&#x751F;&#x5427;&#xFF01;</p>
<p>&#x65BC;&#x662F;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x80FD;&#x6703;&#x60F3;&#xFF0C;&#x65E2;&#x7136; Windows Host &#x90FD;&#x80FD;&#x5982;&#x6B64;&#x9806;&#x66A2;&#x5730;&#x8207; WSL2 &#x4E2D;&#x7684; Podman &#x6574;&#x5408;&#x4E86;&#xFF0C;&#x90A3;&#x9EBC;&#x539F;&#x672C;&#x5C31;&#x5728; WSL2 &#x7684;&#x5176;&#x4ED6; Distro &#x61C9;&#x8A72;&#x53EF;&#x4EE5;&#x66F4;&#x597D;&#x5730;&#x6574;&#x5408;&#x5427;&#x2026;&#x2026;&#x55CE;&#xFF1F;</p>
<p>&#x5F88;&#x53EF;&#x60DC;&#xFF0C;Podman Desktop &#x53EA;&#x4E1F;&#x4E86;&#x4E00;&#x500B;&#x9801;&#x9762;<sup class="footnote-ref"><a href="#fn8" id="fnref8">[8]</a></sup>&#x544A;&#x8A34;&#x4F60;&#xFF0C;&#x4F60;&#x8981;&#x81EA;&#x5DF1;&#x6574;&#x5408;&#x3002;</p>
<p>&#x6574;&#x5408;&#x65B9;&#x5F0F;&#x5927;&#x81F4;&#x5C31;&#x662F;&#x5728; WSL2 &#x4E2D;&#x5B89;&#x88DD;&#x4E00;&#x500B; Podman&#xFF0C;&#x4E26;&#x5C07; <code>podman-machine-default</code> &#x63D0;&#x4F9B;&#x7684; Podman socket &#x63A5;&#x4E0A;&#x9019;&#x500B; Podman&#xFF0C;&#x65B9;&#x6CD5;&#x5982;&#x4E0B;&#xFF1A;</p>
<h3 id="%E5%AE%89%E8%A3%9D-podman-podman-remote">&#x5B89;&#x88DD; Podman / Podman Remote</h3>
<p>Podman Desktop &#x63A8;&#x85A6;&#x5B89;&#x88DD; <code>podman-remote</code><sup class="footnote-ref"><a href="#fn9" id="fnref9">[9]</a></sup> &#x4F5C;&#x70BA;&#x4F60;&#x5728; WSL2 &#x4E2D;&#x4F7F;&#x7528;&#x7684; Podman CLI&#xFF0C;&#x5B89;&#x88DD;&#x65B9;&#x5F0F;&#x4E5F;&#x5F88;&#x7C21;&#x55AE;&#xFF0C;&#x5230; <a href="https://github.com/containers/?ref=blog.davy.tw">containers/podman</a> &#x7684; Release &#x9801;&#x9762;&#x4E2D;&#x4E0B;&#x8F09;&#x9069;&#x5408;&#x7684; <code>podman-remote</code> &#x57F7;&#x884C;&#x6A94;&#x5F8C;&#x653E;&#x5165; <code>$PATH</code>&#xFF08;&#x4F8B;&#x5982; <code>/usr/local/bin</code> &#x6216; <code>/usr/bin</code>&#xFF09; &#x4E2D;&#xFF0C;&#x4E26;&#x5C07; <code>podman</code> alias &#x6210; <code>podman-remote</code> &#x6216;&#x76F4;&#x63A5; <code>ln -s podman-remote podman</code>&#x3002;</p>
<p>&#x63A5;&#x4E0B;&#x4F86;&#x5C31;&#x53EF;&#x4EE5;&#x5617;&#x8A66;&#x5728; WSL2 &#x4E2D;&#x57F7;&#x884C;&#x770B;&#x770B; <code>podman</code>&#xFF08;&#x6216; <code>podman-remote</code>&#xFF09;&#x4E86;&#xFF01;</p>
<pre><code class="language-txt">$ podman-remote ps
Cannot connect to Podman. Please verify your connection to the Linux system using `podman system connection list`, or try `podman machine init` and `podman machine start` to manage a new Linux VM
Error: unable to connect to Podman socket: Get &quot;http://d/v5.1.2/libpod/_ping&quot;: dial unix /mnt/wsl/podman/podman-machine-default.socket: connect: connection refused
</code></pre>
<p>&#x54A6;&#xFF1F;&#x70BA;&#x4EC0;&#x9EBC;&#x4E0D;&#x6703;&#x52D5;&#x5462;&#xFF1F; &#x554A;&#xFF0C;&#x539F;&#x4F86;&#x662F;&#x5FD8;&#x8A18;&#x5C07; <code>podman-remote</code> &#x8207; <code>podman-machine-default</code> &#x4E2D;&#x7684; Podman &#x9023;&#x7D50;&#x5728;&#x4E00;&#x8D77;&#x4E86;&#xFF0C;&#x9084;&#x9700;&#x8981;&#x4E0B;&#x9762;&#x7684;&#x8A2D;&#x5B9A;&#x624D;&#x884C;&#xFF1A;</p>
<pre><code class="language-txt">$ podman-remote system connection add --default \
  podman-machine-default-root \
  unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock
# usermod --append --groups 10 $(whoami)
</code></pre>
<p>&#x8A2D;&#x5B9A;&#x5B8C;&#x6210;&#x4E4B;&#x5F8C;&#x91CD;&#x65B0;&#x767B;&#x5165; Shell&#xFF08;&#x6216;&#x91CD;&#x65B0;&#x6253;&#x958B;&#x4E00;&#x500B;&#x65B0;&#x7684; Terminal&#xFF09;&#xFF0C;&#x518D;&#x57F7;&#x884C;&#x4E00;&#x6B21; <code>podman-remote</code> &#x770B;&#x770B;&#xFF1A;</p>
<pre><code class="language-txt">$ podman-remote ps
CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES
$ podman-remote run --rm quay.io/podman/hello
Trying to pull quay.io/podman/hello:latest...
Getting image source signatures
Copying blob sha256:81df7ff16254ed9756e27c8de9ceb02a9568228fccadbf080f41cc5eb5118a44
Copying config sha256:5dd467fce50b56951185da365b5feee75409968cbab5767b9b59e325fb2ecbc0
Writing manifest to image destination
!... Hello Podman World ...!

         .--&quot;--.
       / -     - \
      / (O)   (O) \
   ~~~| -=(,Y,)=- |
    .---. /`  \   |~~
 ~/  o  o \~~~~.----. ~~
  | =(X)= |~  / (O (O) \
   ~~~~~~~  ~| =(Y_)=-  |
  ~~~~    ~~~|   U      |~~

Project:   https://github.com/containers/podman
Website:   https://podman.io
Desktop:   https://podman-desktop.io
Documents: https://docs.podman.io
YouTube:   https://youtube.com/@Podman
X/Twitter: @Podman_io
Mastodon:  @Podman_io@fosstodon.org
$
</code></pre>
<p>&#x5982;&#x6B64;&#x4E00;&#x4F86;&#x5C31;&#x53EF;&#x4EE5;&#x5728; WSL2 &#x4E2D;&#x64CD;&#x4F5C;&#x8207; Windows &#x6478;&#x5230;&#x7684;&#x540C;&#x4E00;&#x500B; Podman &#x4E86;&#xFF01;</p>
<h3 id="%E6%8E%9B%E8%BC%89-wsl2-%E4%B8%AD%E7%9A%84%E8%B7%AF%E5%BE%91%E8%87%B3-podman">&#x639B;&#x8F09; WSL2 &#x4E2D;&#x7684;&#x8DEF;&#x5F91;&#x81F3; Podman</h3>
<p>&#x5C31;&#x7B97;&#x6309;&#x7167;&#x6B65;&#x9A5F;&#x5C07; WSL2 &#x8207; Podman &#x6574;&#x5408;&#x8D77;&#x4F86;&#x4E4B;&#x5F8C;&#xFF0C;&#x4F60;&#x9084;&#x6703;&#x767C;&#x73FE;&#x4E00;&#x4E9B;&#x5C0F;&#x5C0F;&#x5C0F;&#x554F;&#x984C; &#x2014;&#x2014; &#x4F8B;&#x5982;&#x639B;&#x8F09;&#x4E0D;&#x5230; WSL2 &#x4E2D;&#x7684;&#x76EE;&#x9304;&#x2026;&#x2026;</p>
<pre><code class="language-txt">~/podman-example$ echo &quot;Hello from WSL2&quot; &gt; hello.txt
~/podman-example$ cat `pwd`/hello.txt
Hello from WSL2
~/podman-example$ podman-remote run --rm \
  -v `pwd`/hello.txt:/hello.txt \
  docker.io/library/busybox \
  cat /hello.txt
Error: statfs /home/davy/podman-example/hello.txt: no such file or directory
~/podman-example$
</code></pre>
<p>&#x54A6;&#xFF1F; &#x5947;&#x602A;&#xFF1F; &#x70BA;&#x4EC0;&#x9EBC;&#x4ED6;&#x6703;&#x8DDF;&#x6211;&#x8AAA;&#x9019;&#x500B;&#x6E2C;&#x8A66;&#x7528;&#x7684;&#x6A94;&#x6848;&#x4E0D;&#x5B58;&#x5728;&#xFF0C;&#x660E;&#x660E;&#x76F4;&#x63A5; <code>cat</code> &#x6703;&#x52D5;&#x7684;&#x5440;&#x2026;&#x2026;</p>
<p>&#x800C;&#x4E14;&#x5728; Docker &#x88E1;&#x9762;&#x5982;&#x679C;&#x9019;&#x6A23;&#x5B50;&#x505A;&#x7684;&#x8A71;&#x662F;&#x6703;&#x52D5;&#x7684;&#xFF0C;&#x70BA;&#x4EC0;&#x9EBC;&#x5728; Podman &#x4E2D;&#x4E0D;&#x884C;&#x5462;&#xFF1F;</p>
<p>&#x539F;&#x4F86;&#x662F;&#x5728; Docker Desktop &#x4E2D;&#xFF0C;&#x5C0D;&#x65BC;&#x639B;&#x8F09; WSL2 Distro &#x4E2D;&#x7684;&#x8DEF;&#x5F91;&#x6642;&#xFF0C;Docker &#x6703;&#x8F49;&#x800C;&#x5411;&#x4E00;&#x500B;&#x8F14;&#x52A9;&#x5DE5;&#x5177;&#x6C42;&#x52A9;&#xFF0C;&#x9019;&#x500B;&#x5DE5;&#x5177;&#x6703;&#x5354;&#x52A9; Docker &#x5B58;&#x53D6;&#x5176;&#x4ED6; WSL2 &#x4E2D;&#x7684;&#x8CC7;&#x6599;<sup class="footnote-ref"><a href="#fn10" id="fnref10">[10]</a></sup>&#x3002;&#x56E0;&#x70BA; WSL2 &#x4E2D;&#x5404;&#x500B; Distro &#x7684;&#x8CC7;&#x6599;&#x662F;&#x5404;&#x81EA;&#x7368;&#x7ACB;&#x7684;&#xFF0C;&#x6240;&#x4EE5; Docker/Podman &#x7684; WSL2 &#x9810;&#x8A2D;&#x6C92;&#x6709;&#x8FA6;&#x6CD5;&#x76F4;&#x63A5;&#x5B58;&#x53D6;&#x5176;&#x4ED6; Distro &#x7684;&#x8CC7;&#x6599;&#xFF0C;&#x6B64;&#x6642;&#x6703;&#x5C0E;&#x81F4;&#x639B;&#x8F09;&#x8DEF;&#x5F91;&#x6642;&#x6703;&#x53EA;&#x80FD;&#x5728;&#x81EA;&#x5DF1;&#x7684; WSL2 &#x4E2D;&#x641C;&#x5C0B;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x4F86;&#x505A;&#x500B;&#x5BE6;&#x9A57;&#xFF1A;</p>
<p>&#x6211;&#x5011;&#x5617;&#x8A66;&#x5C07; <code>/home</code> &#x639B;&#x8F09;&#x5230; Podman container &#x4E2D;&#xFF0C;&#x5728;&#x6B64;&#x4E4B;&#x524D;&#x6211;&#x5011;&#x5148;&#x4F86;&#x78BA;&#x8A8D;&#x5728;&#x5169;&#x500B; WSL2 &#x4E2D;&#x7684;&#x6A94;&#x6848;&#x72C0;&#x614B;&#xFF1A;</p>
<pre><code class="language-bash">user@podman-machine-default:~ $ ls /home/
user

davy@Ubuntu:~ $ ls /home/
davy
</code></pre>
<p>&#x63A5;&#x4E0B;&#x4F86;&#x6211;&#x5011;&#x958B;&#x59CB;&#x5617;&#x8A66;&#x639B;&#x8F09;&#xFF1A;</p>
<pre><code class="language-bash">davy@Ubuntu:~ $ podman-remote run --rm -v /home/:/the-home docker.io/library/busybox ls /the-home
user
davy@Ubuntu:~ $
</code></pre>
<p>&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;<code>podman-remote</code> &#x5C07; <code>podman-machine-default</code> &#x4E2D;&#x7684; <code>/home</code> &#x639B;&#x8F09;&#x5230;&#x4E86;&#x5BB9;&#x5668;&#x4E2D;&#xFF0C;&#x800C;&#x975E;&#x6211;&#x5011;&#x671F;&#x671B;&#x7684; WSL2 Distro &#x4E2D;&#x7684; <code>/home</code>&#x3002;</p>
<p>&#x4E5F;&#x5C31;&#x662F;&#x8AAA;&#xFF0C;<code>--volume/-v</code> &#x53C3;&#x6578;&#xFF0C;&#x4E0D;&#x8AD6;&#x5728;&#x90A3;&#x500B; WSL2 Distro&#xFF0C;&#x5C0D;&#x61C9;&#x5230;&#x7684;&#x90FD;&#x662F; <code>podman-machine-default</code> &#x4E2D;&#x7684;&#x8DEF;&#x5F91;&#x3002;</p>
<p>&#x90A3;&#x9EBC;&#xFF0C;&#x6211;&#x5011;&#x8A72;&#x5982;&#x4F55;&#x639B;&#x8F09; WSL2 &#x4E2D;&#x5176;&#x4ED6; Distro &#x7684;&#x8DEF;&#x5F91;&#x5462;&#xFF1F;</p>
<h3 id="wsl2-%E7%9A%84%E7%A5%9E%E5%A5%87%E5%85%B1%E7%94%A8%E7%9B%AE%E9%8C%84">WSL2 &#x7684;&#x795E;&#x5947;&#x5171;&#x7528;&#x76EE;&#x9304;</h3>
<p>&#x5728; WSL2 &#x4E2D;&#xFF0C;&#x6709;&#x4E00;&#x500B;&#x795E;&#x7955;&#x7684;&#x8DEF;&#x5F91;&#x662F;&#x5168; WSL2 Distro &#x5171;&#x4EAB;&#x7684;&#xFF0C;&#x90A3;&#x5C31;&#x662F; <code>/mnt/wsl</code>&#xFF0C;Podman &#x4E5F;&#x662F;&#x85C9;&#x7531;&#x5C07; Podman Engine &#x7684; socket &#x653E;&#x5728;&#x9019;&#x500B;&#x5730;&#x65B9;&#x4F86;&#x8B93;&#x5176;&#x4ED6; Distro &#x53EF;&#x4EE5;&#x5B58;&#x53D6;<sup class="footnote-ref"><a href="#fn11" id="fnref11">[11]</a></sup>&#x3002;WSL2 &#x5C07;&#x9019;&#x500B;&#x795E;&#x5947;&#x76EE;&#x9304;&#x7528;&#x5728;&#x5B58;&#x653E;&#x8207;&#x5168; Distro &#x5171;&#x4EAB;&#x7684;&#x8A2D;&#x5B9A;&#x7B49;&#x8CC7;&#x6599;&#xFF0C;&#x5927;&#x5BB6;&#x53EF;&#x4EE5;&#x5617;&#x8A66;&#x4E0B;&#x9762;&#x7684;&#x6307;&#x4EE4;&#xFF1A;</p>
<pre><code class="language-bash">$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 20 Jul 17 22:11 /etc/resolv.conf -&gt; /mnt/wsl/resolv.conf
$ ls -l /mnt/wsl/resolv.conf
-rw-r--r-- 1 root root 213 Jul 13 09:12 /mnt/wsl/resolv.conf
$ cat /mnt/wsl/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 10.255.255.254
search local
$
</code></pre>
<p>&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x5176;&#x5BE6;&#x6240;&#x6709; Distro &#x7684; <code>/etc/resolv.conf</code><sup class="footnote-ref"><a href="#fn12" id="fnref12">[12]</a></sup>&#xFF0C;&#x90FD;&#x662F;&#x6307;&#x5411; <code>/mnt/wsl/resolv.conf</code>&#xFF0C;&#x800C;&#x9019;&#x500B;&#x6A94;&#x6848;&#x6703;&#x88AB; WSL2 &#x81EA;&#x52D5;&#x5730;&#x66F4;&#x65B0;&#xFF0C;WSL2 &#x85C9;&#x7531;&#x9019;&#x500B;&#x65B9;&#x5F0F;&#x4F86;&#x8B93;&#x6240;&#x6709;&#x7684; Distro &#x5171;&#x7528;&#x76F8;&#x540C;&#x7684;&#x8A2D;&#x5B9A;&#x3002;</p>
<p>&#x65BC;&#x662F;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E;&#x9019;&#x500B;&#x795E;&#x5947;&#x7684;&#x5C0F;&#x5730;&#x65B9;&#x4F86;&#x628A;&#x6211;&#x5011;&#x8981;&#x5206;&#x4EAB;&#x7684;&#x6771;&#x897F;&#x653E;&#x5728;&#x9019;&#x88E1;&#xFF0C;&#x518D;&#x8B93; <code>podman-machine-default</code> &#x4F86;&#x9019;&#x88E1;&#x5B58;&#x53D6;&#x5373;&#x53EF;&#xFF01;</p>
<h1 id="%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%A1%88">&#x89E3;&#x6C7A;&#x65B9;&#x6848;</h1>
<p>&#x65E2;&#x7136;&#x77E5;&#x9053;&#x4E86;&#x65B9;&#x6CD5;&#xFF0C;&#x90A3;&#x9EBC;&#x6211;&#x5011;&#x5C31;&#x5F80;&#x4E0B;&#x4F86;&#x57F7;&#x884C;&#xFF0C;&#x6700;&#x7C21;&#x55AE;&#x7684;&#x65B9;&#x5F0F;&#x5C31;&#x662F;&#x5229;&#x7528; <code>mount</code> &#x6307;&#x4EE4;&#x5C07; WSL2 &#x5404;&#x500B; Distro &#x7684;&#x6839;&#x76EE;&#x9304;&#x5206;&#x4EAB;&#x5230; <code>/mnt/wsl</code> &#x4E0B;&#x9762;&#xFF0C;&#x5982;&#x6B64;&#x4E00;&#x4F86; <code>podman-machine-default</code> &#x5C31;&#x53EF;&#x4EE5;&#x5B58;&#x53D6;&#x5230;&#x88E1;&#x9762;&#x7684;&#x5167;&#x5BB9;&#x4E86;&#xFF01;<sup class="footnote-ref"><a href="#fn13" id="fnref13">[13]</a></sup></p>
<pre><code class="language-bash">$ echo $WSL_DISTRO_NAME
Ubuntu
# mount -t bind -o defaults,bind,X-mount.mkdir / /mnt/wsl/instances/${WSL_DISTRO_NAME}
$ ls /mnt/wsl/instances/
Ubuntu
$ ls /mnt/wsl/instances/Ubuntu/home/
davy
$ podman-remote run --rm \
  -v /mnt/wsl/instances/${WSL_DISTRO_NAME}`pwd`/hello.txt:/hello.txt \
  docker.io/library/busybox \
  cat /hello.txt
Hello from WSL2
$
</code></pre>
<p>&#x7D42;&#x65BC;&#x6210;&#x529F;&#x5566;&#xFF01;&#x1F389;</p>
<h2 id="systemdmount">systemd.mount</h2>
<p>&#x76EE;&#x524D;&#x4E3B;&#x6D41;&#x7248;&#x672C;&#x7684; WSL2 &#x5F15;&#x64CE;&#x90FD;&#x5DF2;&#x7D93;&#x652F;&#x63F4; <code>systemd</code><sup class="footnote-ref"><a href="#fn14" id="fnref14">[14]</a></sup><sup class="footnote-ref"><a href="#fn15" id="fnref15">[15]</a></sup> &#x4E86;&#xFF0C;&#x65BC;&#x662F;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x518D;&#x591A;&#x505A;&#x4E00;&#x9EDE;&#x4E8B;&#x60C5; &#x2014;&#x2014; &#x81EA;&#x52D5;&#x639B;&#x8F09;&#x3002;</p>
<p>&#x7531;&#x65BC;&#x524D;&#x9762;&#x6211;&#x5011;&#x662F;&#x624B;&#x52D5;&#x4F7F;&#x7528; <code>mount</code> &#x6307;&#x4EE4;&#x4F86;&#x9032;&#x884C;&#x639B;&#x8F09;&#xFF0C;&#x5728;&#x6BCF;&#x6B21; WSL2 &#x91CD;&#x65B0;&#x5553;&#x52D5;&#x7684;&#x6642;&#x5019;&#x90FD;&#x6703;&#x5FA9;&#x539F;&#xFF0C;&#x56E0;&#x6B64;&#x6211;&#x5011;&#x5E0C;&#x671B;&#x5728; WSL2 &#x5553;&#x52D5;&#x7684;&#x6642;&#x5019;&#x5C31;&#x5E6B;&#x6211;&#x5011;&#x628A;&#x9019;&#x500B; mountpoint &#x639B;&#x8F09;&#x4E0A;&#x53BB;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E; <code>systemd.mount</code> &#x4F86;&#x5E6B;&#x6211;&#x5011;&#x5B8C;&#x6210;&#x9019;&#x500B;&#x4EFB;&#x52D9;&#x3002;</p>
<p>&#x5728; <code>/etc/systemd/system/</code> &#x4E0B;&#x5EFA;&#x7ACB;&#x4E00;&#x500B;&#x65B0;&#x7684;&#x6A94;&#x6848; <code>mnt-wsl-instances-${WSL_DISTRO_NAME}.mount</code>&#xFF0C;&#x5167;&#x5BB9;&#x5982;&#x4E0B;&#xFF08;&#x6B64;&#x4F8B;&#x4E2D;&#x4EE5; <code>Ubuntu</code> &#x53D6;&#x4EE3; <code>${WSL_DISTRO_NAME}</code>&#xFF0C;&#x8ACB;&#x8B80;&#x8005;&#x81EA;&#x884C;&#x4F9D;&#x7167;&#x81EA;&#x5DF1;&#x7684;&#x74B0;&#x5883;&#x4F5C;&#x66F4;&#x63DB;&#xFF09;&#xFF1A;</p>
<pre><code class="language-ini">[Unit]
Description=WSL Instances

[Mount]
What=/
Where=/mnt/wsl/instances/${WSL_DISTRO_NAME}
Type=none
Options=defaults,bind,X-mount.mkdir

[Install]
WantedBy=multi-user.target
</code></pre>
<p>&#x63A5;&#x4E0B;&#x4F86;&#x57F7;&#x884C;&#x4E0B;&#x5217;&#x6307;&#x4EE4;&#x4F86;&#x5553;&#x7528;&#x9019;&#x500B; mount&#xFF1A;</p>
<pre><code class="language-bash"># umount /mnt/wsl/instances/${WSL_DISTRO_NAME}
$ ls /mnt/wsl/instances/${WSL_DISTRO_NAME}

# systemctl daemon-reload
# systemctl enable --now mnt-wsl-instances-${WSL_DISTRO_NAME}.mount
Created symlink /etc/systemd/system/multi-user.target.wants/mnt-wsl-instances-Ubuntu.mount &#x2192; /etc/systemd/system/mnt-wsl-instances-Ubuntu.mount.
$ ls /mnt/wsl/instances/Ubuntu/home/
davy
$
</code></pre>
<p>&#x9019;&#x6B21;&#x7D42;&#x65BC;&#x662F;&#x5927;&#x529F;&#x544A;&#x6210;&#x4E86;&#xFF01;&#x1F38A;</p>
<h1 id="%E7%B5%90%E8%AA%9E">&#x7D50;&#x8A9E;</h1>
<p>&#x5176;&#x5BE6;&#x539F;&#x672C;&#x4E0D;&#x662F;&#x8981;&#x5BEB; Podman &#x76F8;&#x95DC;&#x7684;&#x5167;&#x5BB9;&#x7684;&#x2026;&#x2026; &#x4F46;&#x525B;&#x597D;&#x9047;&#x5230;&#x8981;&#x4F7F;&#x7528; Podman &#x7684;&#x60C5;&#x666F;&#x5C31;&#x60F3;&#x8AAA;&#x9806;&#x4FBF;&#x628A;&#x9019;&#x4EF6;&#x4E8B;&#x60C5;&#x5BEB;&#x4E0B;&#x4F86;&#x597D;&#x4E86;&#xFF0C;&#x539F;&#x672C;&#x662F;&#x6253;&#x7B97;&#x4E4B;&#x5F8C;&#x518D;&#x8DDF;&#x5927;&#x5BB6;&#x5206;&#x4EAB;&#x7684;&#xFF0C;&#x73FE;&#x5728;&#x63D0;&#x524D;&#x5148;&#x5206;&#x4EAB;&#x7D66;&#x5927;&#x5BB6; :)</p>
<p>Podman &#x5728;&#x74B0;&#x5883;&#x6574;&#x5408;&#x9019;&#x65B9;&#x9762;&#x771F;&#x7684;&#x9084;&#x6C92;&#x6709;&#x505A;&#x7684; Docker &#x597D;&#xFF0C;&#x4F46;&#x9084;&#x7B97;&#x5728;&#x80FD;&#x641E;&#x61C2;&#x539F;&#x7406;&#x7684;&#x60C5;&#x6CC1;&#x4E0B;&#x81EA;&#x884C; Hack&#xFF0C;&#x4F7F;&#x7528;&#x4E0A;&#x6216;&#x8A31;&#x6C92;&#x6709;&#x9019;&#x9EBC;&#x65B9;&#x4FBF;&#xFF0C;&#x4E0D;&#x904E;&#x6211;&#x500B;&#x4EBA;&#x9084;&#x662F;&#x89BA;&#x5F97; Podman &#x9084;&#x7B97;&#x662F;&#x597D;&#x7528;&#x4E14;&#x65B9;&#x4FBF;&#x7684;&#x3002;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x8A73;&#x898B;&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;&#xFF1A; <a href="https://podman.io/?ref=blog.davy.tw">https://podman.io/</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>&#x4EA6;&#x7A31;&#x7D05;&#x5E3D;&#xFF0C;&#x4E3B;&#x529B;&#x958B;&#x767C;&#x53CA;&#x7DAD;&#x8B77;&#x958B;&#x6E90;&#x751F;&#x614B;&#x7684;&#x8EDF;&#x9AD4;&#x516C;&#x53F8;&#xFF0C;&#x5176;&#x767C;&#x884C;&#x7684; Redhat Enterprise Linux &#x5E38;&#x7528;&#x65BC;&#x5404;&#x7A2E;&#x751F;&#x7522;&#x74B0;&#x5883;&#xFF0C;&#x8A73;&#x898B;&#x5176;&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;&#xFF1A; <a href="https://www.redhat.com/?ref=blog.davy.tw">https://www.redhat.com/</a> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>&#x6B64;&#x8655;&#x5C08;&#x6307; Linux Container&#xFF0C;&#x53EF;&#x53C3;&#x898B;&#x7DAD;&#x57FA;&#x767E;&#x79D1;&#x300A;<a href="https://en.wikipedia.org/wiki/Containerization_(computing)?ref=blog.davy.tw">Containerization</a>&#x300B;&#x689D;&#x76EE; <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>&#x5BB9;&#x5668;&#x7BA1;&#x7406;&#x5DE5;&#x5177;&#xFF0C;&#x8A73;&#x898B;&#x5176;&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;&#xFF1A; <a href="https://www.docker.com/?ref=blog.davy.tw">https://www.docker.com/</a> <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p>&#x5148;&#x51FA;&#x73FE;&#x8207; Kubernetes &#x4E2D;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x70BA;&#x4E00;&#x7D44;&#x904B;&#x7B97;&#x8CC7;&#x6E90;&#x7684;&#x6700;&#x5C0F;&#x7BA1;&#x7406;&#x55AE;&#x4F4D;&#xFF0C;&#x5305;&#x542B;&#x7DB2;&#x8DEF;&#x3001;&#x639B;&#x8F09;&#x9EDE;&#x7B49;&#xFF0C;&#x8A73;&#x898B; K8s &#x7684;<a href="https://kubernetes.io/docs/concepts/workloads/pods?ref=blog.davy.tw">&#x6982;&#x5FF5;&#x8AAA;&#x660E;</a> <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p>Podman &#x7684;&#x684C;&#x9762;&#x7BA1;&#x7406;&#x5DE5;&#x5177;&#xFF0C;&#x8A73;&#x898B;&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;&#xFF1A; <a href="https://podman-desktop.io/?ref=blog.davy.tw">https://podman-desktop.io/</a> <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn7" class="footnote-item"><p>Windows Subsystem Linux 2&#xFF0C;&#x4E00;&#x500B;&#x6DF1;&#x5EA6;&#x6574;&#x5408; Linux &#x57F7;&#x884C;&#x74B0;&#x5883;&#x65BC; Windows &#x4E2D;&#x7684;&#x89E3;&#x6C7A;&#x65B9;&#x6848;&#xFF0C;&#x8A2D;&#x8A08;&#x8AAA;&#x660E;&#x8ACB;&#x53C3;&#x95B1;&#xFF1A; <a href="https://learn.microsoft.com/en-us/windows/wsl/compare-versions?ref=blog.davy.tw#whats-new-in-wsl-2">https://learn.microsoft.com/en-us/windows/wsl/compare-versions#whats-new-in-wsl-2</a> <a href="#fnref7" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn8" class="footnote-item"><p>&#x8ACB;&#x898B;&#xFF1A; <a href="https://podman-desktop.io/docs/podman/accessing-podman-from-another-wsl-instance?ref=blog.davy.tw">https://podman-desktop.io/docs/podman/accessing-podman-from-another-wsl-instance</a> <a href="#fnref8" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn9" class="footnote-item"><p>&#x50C5;&#x6709;&#x9060;&#x7AEF;&#x64CD;&#x4F5C; Podman Engine &#x529F;&#x80FD;&#x7684;&#x95B9;&#x5272;&#x7248; Podman CLI&#xFF0C;&#x4F7F;&#x7528;&#x8AAA;&#x660E;&#x8A73;&#x898B;&#xFF1A; <a href="https://docs.podman.io/en/latest/markdown/podman-remote.1.html?ref=blog.davy.tw">https://docs.podman.io/en/latest/markdown/podman-remote.1.html</a> <a href="#fnref9" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn10" class="footnote-item"><p>&#x539F;&#x6587;&#x7BC0;&#x9304; &quot;To make bind-mounts a seamless experience, we introduced a docker api proxy similar to the one we use for enabling bind mounts of Windows files that translates paths relative to the user distro into a path to the same file accessible from the LinuxKit container.&quot;&#xFF0C;&#x5168;&#x6587;&#x8ACB;&#x898B; <a href="https://www.docker.com/blog/new-docker-desktop-wsl2-backend/?ref=blog.davy.tw">https://www.docker.com/blog/new-docker-desktop-wsl2-backend/</a> <a href="#fnref10" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn11" class="footnote-item"><p>Podman &#x5C07; socket &#x653E;&#x5728; <code>/mnt/wsl/podm an-sockets/podman-machine-default/podman-root.sock</code> &#x4F86;&#x8207;&#x5176;&#x4ED6; Distro &#x5171;&#x7528; <a href="#fnref11" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn12" class="footnote-item"><p>Linux &#x4E2D;&#x7528;&#x4F86;&#x8A2D;&#x5B9A; DNS &#x8CC7;&#x8A0A;&#x7684;&#x8A2D;&#x5B9A;&#x6A94;&#xFF0C;&#x8A73;&#x898B; <code>man 5 resolv.conf</code> &#x6216;&#x9019;&#x88E1;&#x7684;&#x5B58;&#x6A94;&#xFF1A; <a href="https://man7.org/linux/man-pages/man5/resolv.conf.5.html?ref=blog.davy.tw">https://man7.org/linux/man-pages/man5/resolv.conf.5.html</a> <a href="#fnref12" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn13" class="footnote-item"><p><code>$WSL_DISTRO_NAME</code> &#x2014;&#x2014; &#x6B64;&#x4E00;&#x74B0;&#x5883;&#x8B8A;&#x6578;&#x6703;&#x8A18;&#x9304;&#x7576;&#x4E0B;&#x74B0;&#x5883;&#x7684; WSL2 Distro &#x540D;&#x7A31; <a href="#fnref13" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn14" class="footnote-item"><p>&#x5728; WSL v0.67.6+ &#x4E2D;&#x53EF;&#x4EE5;&#x5553;&#x7528; <code>systemd</code>&#xFF0C;&#x8A73;&#x898B;&#x5B98;&#x65B9;&#x90E8;&#x843D;&#x683C;&#xFF1A;  <a href="https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/?ref=blog.davy.tw">https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/</a> <a href="#fnref14" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn15" class="footnote-item"><p>&quot;systemd is a suite of basic building blocks for a Linux system. It provides a system and service manager that runs as PID 1 and starts the rest of the system.&quot;&#xFF0C;&#x7BC0;&#x9304;&#x81EA;&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;&#xFF1A; <a href="https://systemd.io/?ref=blog.davy.tw">https://systemd.io/</a> <a href="#fnref15" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[讓 macOS 根據不同 Domain 選擇 DNS 伺服器]]></title><description><![CDATA[由於在 macOS 設定 DNS resolver 的時候，OS 選擇查詢的 resolver 可能不是按照順序的，所以只要有任何一個 resolver 搶先回 NXDOMAIN 就會讓你的查詢找不到 Domain，這對一些有非公開網域或偷偷自定網域的人們來說十分的困擾……]]></description><link>https://blog.davy.tw/posts/dns-resolver-per-domain-on-macos/</link><guid isPermaLink="false">66951cb25cd7770001511574</guid><category><![CDATA[macOS]]></category><category><![CDATA[DNS]]></category><category><![CDATA[Network]]></category><category><![CDATA[resolver]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Mon, 15 Jul 2024 13:31:32 GMT</pubDate><content:encoded><![CDATA[<h1 id="tldr">TL;DR</h1>
<p>&#x5728; <code>/etc/resolver/</code> &#x4E0B;&#x5EFA;&#x7ACB;&#x8207;&#x76EE;&#x6A19; Domain &#x540C;&#x540D;&#x7684;&#x8A2D;&#x5B9A;&#x6A94;&#x3002;</p>
<h1 id="%E8%83%8C%E6%99%AF">&#x80CC;&#x666F;</h1>
<p>&#x7531;&#x65BC;&#x5728; macOS &#x8A2D;&#x5B9A; DNS resolver &#x7684;&#x6642;&#x5019;&#xFF0C;OS &#x9078;&#x64C7;&#x67E5;&#x8A62;&#x7684; resolver &#x53EF;&#x80FD;&#x4E0D;&#x662F;&#x6309;&#x7167;&#x9806;&#x5E8F;&#x7684;&#xFF0C;&#x6240;&#x4EE5;&#x53EA;&#x8981;&#x6709;&#x4EFB;&#x4F55;&#x4E00;&#x500B; resolver &#x6436;&#x5148;&#x56DE; <code>NXDOMAIN</code> &#x5C31;&#x6703;&#x8B93;&#x4F60;&#x7684;&#x67E5;&#x8A62;&#x627E;&#x4E0D;&#x5230; Domain&#xFF0C;&#x9019;&#x5C0D;&#x4E00;&#x4E9B;&#x6709;&#x975E;&#x516C;&#x958B;&#x7DB2;&#x57DF;&#x6216;&#x5077;&#x5077;&#x81EA;&#x5B9A;&#x7DB2;&#x57DF;&#x7684;&#x4EBA;&#x5011;&#x4F86;&#x8AAA;&#x5341;&#x5206;&#x7684;&#x56F0;&#x64FE;&#x3002;</p>
<p>&#x4E00;&#x822C;&#x4F86;&#x8AAA;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x80FD;&#x6703;&#x60F3;&#x8B93; Domain Server &#x5206;&#x6210;&#x5167;&#x5916;&#x5169;&#x7D44;&#xFF0C;&#x628A;&#x53EA;&#x6709;&#x81EA;&#x5DF1;&#x67E5;&#x5F97;&#x5230;&#x7684; domain &#x8B93;&#x5167;&#x90E8;&#x7684; DNS &#x4F86;&#x89E3;&#x6790;&#xFF0C;&#x5269;&#x9918;&#x7684;&#x5176;&#x4ED6;&#x7DB2;&#x57DF;&#x5247;&#x662F;&#x8B93;&#x5916;&#x90E8;&#x7684; DNS &#x4F86;&#x89E3;&#x6790;&#x5C31;&#x597D;&#x4E86;&#xFF0C;&#x7701;&#x53BB;&#x8B93;&#x5167;&#x90E8; DNS &#x505A; recursive &#x7684;&#x9EBB;&#x7169;&#x3002;</p>
<p>&#x4F46;&#x7531;&#x65BC; macOS DNS resolving &#x7684;&#x8A2D;&#x8A08;&#xFF08;&#x6216;&#x6211;&#x5011;&#x8AAA; BSD &#x7684;&#x8A2D;&#x8A08;&#xFF09;&#xFF0C;&#x4F7F;&#x5F97;&#x76F4;&#x63A5;&#x5C07;&#x5168;&#x57DF; DNS &#x8A2D;&#x5B9A;&#x70BA;&#x5167;&#x90E8;&#x512A;&#x5148;&#xFF0C;&#x5916;&#x90E8;&#x6B21;&#x4E4B;&#x7684;&#x9019;&#x4EF6;&#x4E8B;&#x60C5;&#x8B8A;&#x5F97;&#x7121;&#x6CD5;&#x9032;&#x884C;&#xFF0C;&#x6B64;&#x6642;&#x53EF;&#x4EE5;&#x5229;&#x7528;&#x624B;&#x52D5;&#x8A2D;&#x5B9A;&#x7684;&#x65B9;&#x5F0F;&#x4F86;&#x9054;&#x5230;&#x5C07;&#x4E0D;&#x540C; domain &#x6307;&#x5B9A;&#x5230;&#x4E0D;&#x540C; DNS &#x7684;&#x76EE;&#x7684;&#x3002;</p>
<h1 id="resolver5"><code>resolver(5)</code></h1>
<p>&#x5728; <code>man 5 resolver</code><sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> &#x88E1;&#x9762;&#x6709;&#x63D0;&#x5230;&#x4E00;&#x4EF6;&#x4E8B;&#x60C5;&#xFF0C;<code>/etc/resolv.conf</code> &#x8A18;&#x9304;&#x7684;&#x662F;&#x300C;&#x4E3B;&#x8981;&#x7684;&#x300D;DNS resolver &#x8A2D;&#x5B9A;<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>&#xFF0C;&#x4F46;&#x5176;&#x5BE6;&#x6240;&#x6709;&#x7684;&#x8A2D;&#x5B9A;&#x9664;&#x4E86;&#x6703;&#x5F9E; <code>/etc/resolv.conf</code> &#x8B80;&#x53D6;&#x4EE5;&#x5916;&#xFF0C;&#x9084;&#x6703;&#x5F9E; <code>/etc/resolver/</code> &#x76EE;&#x9304;&#x4E0B;&#x9762;&#x8B80;&#x53D6;<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>&#x3002;</p>
<p>&#x5C0D;&#x65BC;&#x9019;&#x500B;&#x76EE;&#x9304;&#x88E1;&#x9762;&#x7684;&#x8A2D;&#x5B9A;&#x6A94;&#x9664;&#x4E86;&#x8207; <code>resolv.conf</code> &#x683C;&#x5F0F;&#x4E00;&#x81F4;&#x4EE5;&#x5916;&#xFF0C;&#x9084;&#x6709;&#x4E00;&#x500B;&#x9650;&#x5236;&#x662F;&#x6A94;&#x540D;&#x5FC5;&#x9808;&#x8207;&#x8981;&#x641C;&#x5C0B;&#x7684; domain &#x540C;&#x540D;&#xFF0C;&#x5728;&#x95DC;&#x65BC; <code>domain</code> &#x7684;&#x9019;&#x500B;&#x8A2D;&#x5B9A;&#x503C;&#x7684;&#x8AAA;&#x660E;&#x662F;&#x9019;&#x6A23;&#x8AAA;&#x7684;&#xFF1A;</p>
<blockquote>
<p>Domain</p>
<p>Domain name associated with this resolver configuration. This option is normally not required	by the Mac OS X	DNS search system when the resolver configuration is read from a file in the /etc/resolver directory.<br>
In that case the file name is used as the	domain name.</p>
<p>However, &quot;domain&quot; must be provided when there are multiple resolver clients for the same domain name, since multiple files may not exist having the same name.</p>
</blockquote>
<p>&#x4E5F;&#x5C31;&#x662F;&#x8AAA;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x5728; <code>/etc/resolver/</code> &#x4E0B;&#x5EFA;&#x7ACB;&#x65BC;&#x6211;&#x5011;&#x60F3;&#x8981;&#x984D;&#x5916;&#x8A2D;&#x5B9A;&#x500B;&#x5225;&#x7DB2;&#x57DF;&#x7684; resolver &#x8A2D;&#x5B9A;&#x6A94;&#x3002;&#x65B9;&#x6CD5;&#x4E5F;&#x5F88;&#x7C21;&#x55AE;&#xFF0C;&#x6211;&#x5011;&#x63A5;&#x4E0B;&#x4F86;&#x5C31;&#x4F86;&#x5617;&#x8A66;&#x505A;&#x9EDE;&#x5BE6;&#x9A57;&#xFF1A;</p>
<h1 id="etcresolver"><code>/etc/resolver/</code></h1>
<p>&#x5047;&#x5B9A;&#x6211;&#x5011;&#x60F3;&#x8981;&#x500B;&#x5225;&#x8A2D;&#x5B9A;&#x7684;&#x7DB2;&#x57DF;&#x70BA; <code>davy.home</code>&#xFF08;&#x7576;&#x7136;&#xFF0C;&#x9019;&#x500B;&#x7DB2;&#x57DF;&#x5BE6;&#x969B;&#x4E0A;&#x4E26;&#x4E0D;&#x5B58;&#x5728;&#x65BC;&#x9019;&#x500B;&#x4E16;&#x754C;&#x4E0A;&#xFF09;&#xFF0C;&#x90A3;&#x9EBC;&#x6211;&#x5011;&#x53EA;&#x9700;&#x8981;&#x5EFA;&#x7ACB; <code>/etc/resolver/davy.home</code><sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup> &#x9019;&#x500B;&#x6A94;&#x6848;&#x5373;&#x53EF;&#xFF0C;&#x5167;&#x5BB9;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code>domain davy.home
search davy.home
nameserver 10.10.10.10
nameserver 10.10.10.100
</code></pre>
<p>&#x5728;&#x9019;&#x500B;&#x7BC4;&#x4F8B;&#x4E2D;&#xFF0C;&#x6211;&#x8A2D;&#x5B9A;&#x4E86;&#x5169;&#x7D44; <code>nameserver</code> &#x5206;&#x5225;&#x662F; <code>10.10.10.10</code> &#x8207; <code>10.10.10.100</code>&#xFF0C;&#x5927;&#x5BB6;&#x53EF;&#x4EE5;&#x6839;&#x64DA;&#x81EA;&#x5DF1;&#x7684;&#x5BE6;&#x969B;&#x60C5;&#x6CC1;&#x8A2D;&#x5B9A;&#x3002;</p>
<p>&#x96D6;&#x7136;&#x6587;&#x4EF6;&#x4E2D;&#x5BEB;&#x8AAA; <code>domain</code> &#x5728; macOS &#x4E2D;&#x4E0D;&#x662F;&#x5FC5;&#x9808;&#x7684;&#xFF0C;&#x4F46;&#x6211;&#x9084;&#x662F;&#x6309;&#x7167;&#x586B;&#x5BEB;&#x7684;&#x898F;&#x5247;&#x5BEB;&#x4E0A;&#x4E86; <code>davy.home</code>&#xFF0C;&#x5404;&#x4F4D;&#x8B80;&#x8005;&#x53EF;&#x4EE5;&#x81EA;&#x884C;&#x5617;&#x8A66;&#x5C07;&#x6B64;&#x6B04;&#x4F4D;&#x79FB;&#x9664;&#x662F;&#x5426;&#x4ECD;&#x7136;&#x6703;&#x751F;&#x6548;&#x3002;</p>
<p>&#x63A5;&#x4E0B;&#x4F86;&#x6211;&#x5011;&#x6703;&#x6E05;&#x9664; macOS &#x7684; DNS cache &#x4E26;&#x6AA2;&#x67E5;&#x770B;&#x770B;&#x8A2D;&#x5B9A;&#x5F8C;&#x7684;&#x7D50;&#x679C;&#x662F;&#x5426;&#x8207;&#x6211;&#x5011;&#x60F3;&#x50CF;&#x7684;&#x4E00;&#x6A23;&#xFF1A;</p>
<pre><code class="language-bash"># killall -HUP mDNSResponder
$ scutil --dns
DNS configuration
...
resolver #8
  domain   : davy.home
  search domain[0] : davy.home
  nameserver[0] : 10.10.10.10
  nameserver[1] : 10.10.10.100
  flags    : Request A records
  reach    : 0x00000002 (Reachable)
...
$
</code></pre>
<p>&#x900F;&#x904E; <code>scutil</code><sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup> &#x53EF;&#x4EE5;&#x78BA;&#x8A8D;&#x7CFB;&#x7D71;&#x7684; resolver &#x5DF2;&#x7D93;&#x7279;&#x5316;&#x51FA;&#x7D66; <code>davy.home</code> &#x4F7F;&#x7528;&#x7684;&#x8A2D;&#x5B9A;&#x4E86;&#xFF0C;&#x6B64;&#x6642;&#x5927;&#x5BB6;&#x5C31;&#x53EF;&#x4EE5;&#x5728;&#x4E0D;&#x6539;&#x8B8A; Global resolver &#x7684;&#x60C5;&#x6CC1;&#x4E0B;&#x4F86;&#x7A69;&#x5B9A;&#x67E5;&#x8A62; <code>davy.home</code> &#x4E86;&#x3002;</p>
<h1 id="%E7%B5%90%E8%AA%9E">&#x7D50;&#x8A9E;</h1>
<p>&#x900F;&#x904E;&#x7368;&#x7ACB; DNS resolver &#x7684;&#x8A2D;&#x5B9A;&#x8B93;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x6307;&#x5B9A;&#x4E0D;&#x540C;&#x7DB2;&#x57DF;&#x7684;&#x67E5;&#x8A62;&#x65B9;&#x5F0F;&#xFF0C;&#x4E5F;&#x53EF;&#x4EE5;&#x8B93;&#x6211;&#x5011;&#x7684; Domain Server &#x6E1B;&#x53BB;&#x4E86;&#x4E0D;&#x5FC5;&#x8981;&#x7684; recursion &#x7684;&#x8CA0;&#x64D4;&#xFF0C;&#x5C0D;&#x65BC;&#x6211;&#x5011;&#x9019;&#x7A2E;&#x53EF;&#x80FD;&#x6703;&#x6709;&#x4E00;&#x4E9B;&#x5BE6;&#x9A57;&#x7528;&#x7684;&#x79C1;&#x4EBA;&#x7DB2;&#x57DF;&#x4F86;&#x8AAA;&#xFF0C;&#x6BD4;&#x8D77;&#x5176;&#x4ED6;&#x7CFB;&#x7D71;&#x6703;&#x5FAA;&#x5E8F;&#x67E5;&#x8A62; resolver &#x7684;&#x65B9;&#x5F0F;&#x771F;&#x7684;&#x662F;&#x65B9;&#x4FBF;&#x4E86;&#x4E0D;&#x5C11;&#x3002;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x6B64;&#x8655;&#x6307;&#x7684;&#x662F; macOS &#x7684; <code>resolver(5)</code> &#x689D;&#x76EE;&#xFF0C;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x900F;&#x904E; <code>man 5 resolver</code> &#x67E5;&#x95B1;&#x5167;&#x5BB9;&#xFF0C;&#x6216;&#x53C3;&#x8003; <a href="https://man.freebsd.org/cgi/man.cgi?query=resolver&amp;sektion=5&amp;manpath=macOS+14.3.1&amp;ref=blog.davy.tw">FreeBSD &#x6536;&#x9304;&#x7684;&#x6A94;&#x6848;&#x5167;&#x5BB9;</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>&#x539F;&#x6587;&#x70BA; &quot;Note that the /etc/resolv.conf file, which contains configuration for the default (or &quot;primary&quot;) DNS resolver client, is maintained automatically by Mac OS X and should not be edited manually. Changes to the DNS configuration should be made by using the Network Preferences panel.&quot; <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>&#x539F;&#x6587;&#x70BA; &quot;These are	at present located by the system in the /etc/resolv.conf file and in the files found in the /etc/resolver directory.&quot; <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>&#x9810;&#x8A2D;&#x60C5;&#x6CC1;&#x4E0B; <code>/etc/resolver/</code> &#x9019;&#x500B;&#x76EE;&#x9304;&#x4E26;&#x4E0D;&#x5B58;&#x5728;&#xFF0C;&#x5927;&#x5BB6;&#x81EA;&#x884C;&#x65B0;&#x589E;&#x5373;&#x53EF; <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p>&#x95DC;&#x65BC; <code>scutil</code> &#x7684;&#x4F7F;&#x7528;&#x8AAA;&#x660E;&#x53EF;&#x4EE5;&#x5F9E; <code>man 8 scutil</code> &#x6216; <a href="https://man.freebsd.org/cgi/man.cgi?query=scutil&amp;apropos=0&amp;sektion=0&amp;manpath=macOS+14.3.1&amp;arch=default&amp;format=html&amp;ref=blog.davy.tw">FreeBSD &#x7684;&#x6536;&#x9304;&#x7684;&#x8AAA;&#x660E;</a>&#x67E5;&#x95B1; <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[macOS 神奇的 terminal compat mode]]></title><description><![CDATA[為什麼 macOS 的 less 明明在 manpage 中寫有 s (save log) 可以用，但實際按下去卻是往下捲一行]]></description><link>https://blog.davy.tw/posts/unix-03-compat-mode-in-macos/</link><guid isPermaLink="false">614f3c8a56deeb000160a8db</guid><category><![CDATA[macOS]]></category><category><![CDATA[UNIX]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Sun, 10 Oct 2021 16:50:24 GMT</pubDate><content:encoded><![CDATA[<blockquote>
<p>TL;DR macOS &#x5167;&#x5EFA;&#x4E86;&#x4E00;&#x500B; compat mode &#x53EF;&#x4EE5;&#x4F7F;&#x5F97;&#x90E8;&#x5206; CLI &#x5DE5;&#x5177;&#x4EE5; SUSv3 &#x76F8;&#x5BB9;&#x6A21;&#x5F0F;&#x57F7;&#x884C;&#xFF0C;&#x8A66;&#x8A66;&#x770B; <code>COMMAND_MODE=[legacy|unix2003]</code></p>
</blockquote>
<p>&#x67D0;&#x5929;&#x5F37;&#x8005;&#x6211;&#x670B;&#x53CB;&#x5728;&#x793E;&#x7FA4;&#x8EDF;&#x9AD4;&#x4E0A;&#x9762;&#x554F;&#x4E86;&#x70BA;&#x4EC0;&#x9EBC; macOS &#x7684; less &#x660E;&#x660E;&#x5728; manpage &#x4E2D;&#x5BEB;&#x6709; s (save log) &#x53EF;&#x4EE5;&#x7528;&#xFF0C;&#x4F46;&#x5BE6;&#x969B;&#x6309;&#x4E0B;&#x53BB;&#x537B;&#x662F;&#x5F80;&#x4E0B;&#x6372;&#x4E00;&#x884C;&#x2026;&#x2026;</p>
<p>&#x6211;&#x7B2C;&#x4E00;&#x500B;&#x60F3;&#x6CD5;&#x7576;&#x7136;&#x662F;&#x5148;&#x770B;&#x7A0B;&#x5F0F;&#x78BC;&#x518D;&#x8AAA;&#xFF0C;&#x770B;&#x770B;&#x662F;&#x4E0D;&#x662F;&#x6709;&#x4EC0;&#x9EBC;&#x96B1;&#x85CF;&#x8A2D;&#x5B9A;&#xFF0C;&#x4F46;&#x6211;&#x4E00;&#x958B;&#x59CB;&#x770B;&#x4E86;&#x539F;&#x7248;&#x7684; less &#x767C;&#x73FE;&#x6C92;&#x4EC0;&#x9EBC;&#x53EF;&#x7591;&#x7684;&#x5730;&#x65B9;&#xFF0C;&#x65BC;&#x662F;&#x6211;&#x8F49;&#x5FF5;&#x4E00;&#x60F3;&#xFF0C;&#x90A3;&#x9019;&#x8AAA;&#x4E0D;&#x5B9A;&#x662F; Apple &#x505A;&#x7684;&#x4EC0;&#x9EBC;&#x795E;&#x5947;&#x529F;&#x80FD;&#xFF1F; &#x597D;&#x5728; less &#x662F; GPL &#x6388;&#x6B0A;&#xFF0C;Apple &#x6309;&#x7167;&#x898F;&#x5B9A;&#x61C9;&#x8A72;&#x8981;&#x653E;&#x51FA;&#x539F;&#x59CB;&#x78BC;&#x4F86;&#x7D66;&#x5927;&#x5BB6;&#x3002;</p>
<p>&#x65BC;&#x662F;&#x6211;&#x5C31;&#x627E;&#x5230;&#x4E86;&#x4E00;&#x500B;&#x7248;&#x672C;&#x6BD4;&#x8F03;&#x820A;&#x7684;&#xFF08;less-34&#xFF09;&#x539F;&#x59CB;&#x78BC;&#xFF08;&#x6211;&#x4E0D;&#x77E5;&#x9053;&#x70BA;&#x4EC0;&#x9EBC;&#x73FE;&#x5728; macOS &#x5167;&#x5EFA;&#x7684;&#x5DF2;&#x7D93;&#x5230; 100 &#x591A;&#x7248;&#x4E86;&#xFF0C;&#x4F46;&#x653E;&#x51FA;&#x4F86;&#x7684;&#x53EA;&#x6709; v34&#x2026;&#x2026;&#xFF09;&#xFF0C;&#x800C;&#x4E14;&#x9084;&#x771F;&#x7684;&#x88AB;&#x6211;&#x627E;&#x5230;&#x4E86;&#x4E00;&#x500B;&#x53EF;&#x7591;&#x7684;&#x5730;&#x65B9;<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>&#xFF1A;</p>
<pre><code class="language-c">/* 
 * Command table for UNIX 2003 compatibility: added first before builtin
 * so that these commands override the normal LESS commands
 */

static unsigned char UNIX03cmdtable[] =
{
	&apos;s&apos;,0,				A_F_LINE
};
</code></pre>
<p>Apple &#x5728;&#x9019;&#x500B;&#x5730;&#x65B9;&#x65B0;&#x589E;&#x4E86;&#x4E00;&#x500B;&#x6309;&#x9375;&#x6620;&#x5C04;&#xFF0C;&#x4E26;&#x4E14;&#x5BEB;&#x4E86;&#x4E00;&#x6BB5;&#x8A3B;&#x89E3;&#x544A;&#x8A34;&#x6211;&#x5011;&#xFF0C;&#x9019;&#x500B;&#x6309;&#x9375;&#x8986;&#x84CB;&#x9810;&#x8A2D;&#x7684; less &#x6307;&#x4EE4;&#x3002; &#x70BA;&#x4F55; Apple &#x5728;&#x9019;&#x88E1;&#x591A;&#x4E86;&#x4E00;&#x500B;&#x5947;&#x602A;&#x7684;&#x884C;&#x70BA;&#x5462;&#xFF1F; &#x539F;&#x4F86;&#x662F; Apple &#x5F9E; Mac OS X 10.3 &#x5C31;&#x958B;&#x59CB;&#x5728;&#x5167;&#x5EFA;&#x7684; CLI tools &#x88E1;&#x9762;&#x65B0;&#x589E;&#x4E86;&#x9019;&#x500B; Single UNIX Specification v3 (SUSv3)<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x76F8;&#x5BB9;&#x6A21;&#x5F0F;&#xFF0C;&#x800C;&#x67D0;&#x4E9B;&#x7D42;&#x7AEF;&#x6A5F;&#x8EDF;&#x9AD4;&#x9810;&#x8A2D;&#x5C31;&#x6703;&#x628A;&#x9019;&#x500B;&#x6A21;&#x5F0F;&#x958B;&#x5553;&#xFF08;&#x4F8B;&#x5982; iTerm2&#xFF09;&#x800C;&#x5C0E;&#x81F4; less &#x7B49;&#x5DE5;&#x5177;&#x7684;&#x884C;&#x70BA;&#x8207;&#x6211;&#x5011;&#x60F3;&#x50CF;&#x4E2D;&#x7684;&#x4E0D;&#x592A;&#x4E00;&#x6A23;&#x3002;</p>
<p>&#x5728;&#x7FFB;&#x95B1;&#x4E86;&#x6587;&#x4EF6;<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>&#x4EE5;&#x53CA;&#x7DB2;&#x8DEF;&#x8CC7;&#x6599;<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>&#x4E4B;&#x5F8C;&#x767C;&#x73FE;&#xFF0C;&#x53EA;&#x8981;&#x900F;&#x904E;&#x74B0;&#x5883;&#x8B8A;&#x6578;&#x5C31;&#x53EF;&#x4EE5;&#x63A7;&#x5236;&#x9019;&#x500B;&#x76F8;&#x5BB9;&#x6A21;&#x5F0F;&#x7684;&#x958B;&#x5553;&#x8207;&#x5426;&#xFF0C;&#x65BC;&#x662F;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E;&#x8A2D;&#x5B9A; <code>COMMAND_MODE</code> &#x9019;&#x500B;&#x74B0;&#x5883;&#x8B8A;&#x6578;&#x4F86;&#x958B;&#x95DC;&#x76F8;&#x5BB9;&#x6A21;&#x5F0F;&#xFF1A;</p>
<pre><code class="language-bash">$ # &#x4F7F;&#x7528; SUSv3 &#x76F8;&#x5BB9;&#x6A21;&#x5F0F;
$ COMMAND_MODE=unix2003 less file.txt
$ # &#x4E0D;&#x4F7F;&#x7528;&#x76F8;&#x5BB9;&#x6A21;&#x5F0F;
$ COMMAND_MODE=legacy less file.txt
</code></pre>
<p>&#x65BC;&#x662F;&#x95DC;&#x6389;&#x76F8;&#x5BB9;&#x6A21;&#x5F0F;&#x4E4B;&#x5F8C;&#x5C31;&#x53EF;&#x4EE5;&#x6109;&#x5FEB;&#x7684;&#x5728; less &#x4E2D;&#x4F7F;&#x7528; s &#x4F86; save log file &#x4E86;&#xFF01;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x898B; <a href="https://opensource.apple.com/source/less/less-34/less/decode.c.auto.html?ref=blog.davy.tw">decode.c</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>&#x8A73;&#x898B;&#x7DAD;&#x57FA;&#x767E;&#x79D1;<a href="https://en.wikipedia.org/wiki/Single_UNIX_Specification?ref=blog.davy.tw#Marks_for_compliant_systems">&#x3008;Single UNIX Specification&#x3009;</a>&#x689D;&#x76EE; <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>&#x898B; <code>man 5 compat</code> <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p><a href="https://www.oradba.ch/2011/04/mac-os-x-terminal-compatibility-settings/?ref=blog.davy.tw">https://www.oradba.ch/2011/04/mac-os-x-terminal-compatibility-settings/</a> <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[使用 M1 Mac 的一些小技巧]]></title><description><![CDATA[前幾天拿到了新的 M1 MacBook Air，想說來試試看一些平常使用的工具以及 iOS App，結果發現很多常用的 iOS App 都還沒有開放 macOS 下載使用…… 但很多常用的工具都已經有原生支援的版本了，在使用上也沒有什麼太多的問題，但有些小技巧想分享給大家，希望大家在這個轉換之路上可以再更順暢一些~]]></description><link>https://blog.davy.tw/posts/tips-on-m1-mac/</link><guid isPermaLink="false">600c008b8b52a70001c227f9</guid><category><![CDATA[macOS]]></category><category><![CDATA[M1]]></category><category><![CDATA[Rosetta 2]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Sat, 23 Jan 2021 12:54:58 GMT</pubDate><media:content url="https://blog.davy.tw/content/images/2021/01/---2021-01-23---8.57.05.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.davy.tw/content/images/2021/01/---2021-01-23---8.57.05.png" alt="&#x4F7F;&#x7528; M1 Mac &#x7684;&#x4E00;&#x4E9B;&#x5C0F;&#x6280;&#x5DE7;"><p>&#x524D;&#x5E7E;&#x5929;&#x62FF;&#x5230;&#x4E86;&#x65B0;&#x7684; M1 MacBook Air&#xFF0C;&#x60F3;&#x8AAA;&#x4F86;&#x8A66;&#x8A66;&#x770B;&#x4E00;&#x4E9B;&#x5E73;&#x5E38;&#x4F7F;&#x7528;&#x7684;&#x5DE5;&#x5177;&#x4EE5;&#x53CA; iOS App&#xFF0C;&#x7D50;&#x679C;&#x767C;&#x73FE;&#x5F88;&#x591A;&#x5E38;&#x7528;&#x7684; iOS App &#x90FD;&#x9084;&#x6C92;&#x6709;&#x958B;&#x653E; macOS &#x4E0B;&#x8F09;&#x4F7F;&#x7528;&#x2026;&#x2026; &#x4F46;&#x5F88;&#x591A;&#x5E38;&#x7528;&#x7684;&#x5DE5;&#x5177;&#x90FD;&#x5DF2;&#x7D93;&#x6709;&#x539F;&#x751F;&#x652F;&#x63F4;&#x7684;&#x7248;&#x672C;&#x4E86;&#xFF0C;&#x5728;&#x4F7F;&#x7528;&#x4E0A;&#x4E5F;&#x6C92;&#x6709;&#x4EC0;&#x9EBC;&#x592A;&#x591A;&#x7684;&#x554F;&#x984C;&#xFF0C;&#x4F46;&#x6709;&#x4E9B;&#x5C0F;&#x6280;&#x5DE7;&#x60F3;&#x5206;&#x4EAB;&#x7D66;&#x5927;&#x5BB6;&#xFF0C;&#x5E0C;&#x671B;&#x5927;&#x5BB6;&#x5728;&#x9019;&#x500B;&#x8F49;&#x63DB;&#x4E4B;&#x8DEF;&#xFF08;&#xFF1F;&#xFF09;&#x4E0A;&#x53EF;&#x4EE5;&#x518D;&#x66F4;&#x9806;&#x66A2;&#x4E00;&#x4E9B;~</p>
<ul>
<li><a href="#rosetta2">Rosetta 2 &#x76F8;&#x95DC;</a></li>
<li><a href="#iosapp">iOS App &#x76F8;&#x95DC;</a></li>
<li><a href="#cli">CLI &#x76F8;&#x95DC;</a></li>
<li><a href="#%E9%9B%9C%E8%A8%98">&#x96DC;&#x8A18;</a></li>
</ul>
<h2 id="rosetta-2-%E7%9B%B8%E9%97%9C">Rosetta 2 &#x76F8;&#x95DC;</h2>
<p>&#x9019;&#x88E1;&#x6703;&#x5217;&#x51FA;&#x4E00;&#x4E9B;&#x8207; Intel &#x76F8;&#x5BB9;&#x6A21;&#x5F0F;&#xFF08;Rosetta 2&#xFF09;&#x6709;&#x95DC;&#x7684;&#x4E00;&#x4E9B;&#x5C0F;&#x6280;&#x5DE7;&#xFF1A;</p>
<h3 id="%E5%8E%9F%E7%94%9F%E6%94%AF%E6%8F%B4%EF%BC%9F">&#x539F;&#x751F;&#x652F;&#x63F4;&#xFF1F;</h3>
<p>&#x5728;&#x6D3B;&#x52D5;&#x76E3;&#x8996;&#x5668;&#xFF08;Activity Monitor&#xFF09;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x4E00;&#x500B;&#x53EB;&#x505A;&#x300C;&#x5EFA;&#x7BC9;&#x300D;<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>&#x7684;&#x6B04;&#x4F4D;&#xFF0C;&#x5728;&#x9019;&#x88E1;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x6709;&#x5206;&#x6210; Apple &#x4EE5;&#x53CA; Intel&#xFF0C;&#x5206;&#x5225;&#x5C0D;&#x61C9;&#x5230;&#x539F;&#x751F; Apple silicon &#x4EE5;&#x53CA; Rosetta 2<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x76F8;&#x5BB9;&#x7684; Intel &#x6A21;&#x5F0F;&#x3002;</p>
<p><img src="https://i.imgur.com/3qOOfJZ.png" alt="&#x4F7F;&#x7528; M1 Mac &#x7684;&#x4E00;&#x4E9B;&#x5C0F;&#x6280;&#x5DE7;" loading="lazy"></p>
<p>&#x5982;&#x679C;&#x4F60;&#x767C;&#x73FE;&#x6B63;&#x5728;&#x57F7;&#x884C;&#x7684;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x662F; Intel &#x8868;&#x793A;&#x4ED6;&#x6B63;&#x5728; Rosetta 2 &#x5E95;&#x4E0B;&#x904B;&#x4F5C;&#x3002;</p>
<h3 id="%E6%89%8B%E5%8B%95%E5%AE%89%E8%A3%9D-rosetta-2">&#x624B;&#x52D5;&#x5B89;&#x88DD; Rosetta 2</h3>
<p>&#x500B;&#x4EBA;&#x89BA;&#x5F97;&#x9019;&#x500B;&#x6280;&#x5DE7;&#x81F3;&#x95DC;&#x91CD;&#x8981;&#xFF0C;&#x56E0;&#x70BA;&#x6211;&#x66FE;&#x7D93;&#x5728; 11.0.1 &#x5347;&#x7D1A;&#x5230; 11.1 &#x4E4B;&#x5F8C;&#xFF0C;Rosetta &#x5C31;&#x6D88;&#x5931;&#x4E86;&#xFF0C;&#x5C0E;&#x81F4;&#x6211;&#x9084;&#x5728;&#x7528; Intel &#x67B6;&#x69CB;&#x7684;&#x8F38;&#x5165;&#x6CD5;&#xFF08;&#x5C0D;&#xFF01;&#x9023;&#x8F38;&#x5165;&#x6CD5;&#x90FD;&#x53EF;&#x4EE5;&#x9760; Rosetta &#x76F8;&#x5BB9;&#xFF09;&#x6B7B;&#x4EA1;&#xFF0C;&#x4E5F;&#x4E0D;&#x77E5;&#x9053;&#x70BA;&#x4EC0;&#x9EBC; macOS &#x6C92;&#x6709;&#x4E3B;&#x52D5;&#x63D0;&#x9192;&#x6211;&#x8981;&#x518D;&#x5B89;&#x88DD;&#x4E00;&#x6B21; Rosetta&#xFF0C;&#x76F4;&#x5230;&#x6211;&#x8981;&#x5B89;&#x88DD;&#x5225;&#x7684; Intel &#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x6642;&#x624D;&#x53C8;&#x63D0;&#x9192;&#xFF0C;&#x7576;&#x6642;&#x6211;&#x624D;&#x604D;&#x7136;&#x5927;&#x609F;&#xFF0C;&#x539F;&#x4F86;&#x6211;&#x7684; Rosetta &#x5728;&#x5347;&#x7D1A;&#x7684;&#x6642;&#x5019;&#x6D88;&#x5931;&#x4E86;&#x2026;&#x2026;</p>
<p>&#x65B9;&#x6CD5;&#x4E5F;&#x5F88;&#x7C21;&#x55AE;&#xFF0C;&#x53EA;&#x8981;&#x6253;&#x958B;&#x7D42;&#x7AEF;&#x6A5F;&#x7136;&#x5F8C;&#x7528;&#x8EDF;&#x9AD4;&#x5347;&#x7D1A;&#x7684;&#x65B9;&#x5F0F;&#x5B89;&#x88DD;&#x5C31;&#x53EF;&#x4EE5;&#x4E86;&#xFF1A;</p>
<pre><code class="language-bash">$ /usr/sbin/softwareupdate --install-rosetta --agree-to-license
</code></pre>
<p>&#x96D6;&#x7136;&#x52A0;&#x4E86; <code>--agree-to-license</code> &#x4E4B;&#x5F8C;&#x5C31;&#x4E0D;&#x6703;&#x63D0;&#x9192;&#x4F60;&#x518D;&#x770B;&#x4E00;&#x6B21; SLA&#xFF0C;&#x4F46;&#x7B2C;&#x4E00;&#x6B21;&#x4F7F;&#x7528;&#x524D;&#x9084;&#x662F;&#x770B;&#x4E00;&#x4E0B;&#x5427;XD</p>
<h3 id="%E5%BC%B7%E5%88%B6%E4%BD%BF%E7%94%A8-rosetta-%E4%BE%86%E5%9F%B7%E8%A1%8C-universal-%E6%87%89%E7%94%A8%E7%A8%8B%E5%BC%8F">&#x5F37;&#x5236;&#x4F7F;&#x7528; Rosetta &#x4F86;&#x57F7;&#x884C; Universal &#x61C9;&#x7528;&#x7A0B;&#x5F0F;</h3>
<div>
    <img src="https://i.imgur.com/djiosjn.png" style="max-width: 300px; float: right;" alt="&#x4F7F;&#x7528; M1 Mac &#x7684;&#x4E00;&#x4E9B;&#x5C0F;&#x6280;&#x5DE7;">
</div>
<p>&#x860B;&#x679C;&#x5728;&#x8F49;&#x63DB;&#x5230; Apple silicon &#x7684;&#x6642;&#x5019;&#x63D0;&#x51FA;&#x4E86;&#x4E00;&#x500B;&#x4EE5;&#x524D;<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>&#x4E5F;&#x7528;&#x904E;&#x7684;&#x89E3;&#x6C7A;&#x65B9;&#x6848;&#xFF0C;&#x5C0D;&#x65BC;&#x9019;&#x6A23;&#x7684;&#x901A;&#x7528;&#x67B6;&#x69CB;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E;&#x300C;&#x53D6;&#x5F97;&#x8CC7;&#x8A0A;&#x300D;&#x4F86;&#x5C07;&#x901A;&#x7528;&#x67B6;&#x69CB;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x8A2D;&#x5B9A;&#x70BA;&#x4F7F;&#x7528; Rosetta &#x958B;&#x5553;&#x3002;</p>
<h3 id="%E9%80%8F%E9%81%8E-cli-%E5%BC%B7%E5%88%B6%E4%BD%BF%E7%94%A8-rosetta">&#x900F;&#x904E; CLI &#x5F37;&#x5236;&#x4F7F;&#x7528; Rosetta</h3>
<p>&#x524D;&#x9762;&#x8B1B;&#x7684;&#x662F;&#x53EF;&#x4EE5;&#x5C07; .app &#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x4EE5; Rosetta &#x65B9;&#x5F0F;&#x958B;&#x5553;&#x7684;&#x6280;&#x5DE7;&#xFF0C;&#x4F46;&#x5982;&#x679C;&#x5728; CLI &#x4E0B;&#x7684;&#x8A71;&#x8A72;&#x5982;&#x4F55;&#x64CD;&#x4F5C;&#x5462;&#xFF1F;</p>
<p>&#x65B9;&#x6CD5;&#x4E5F;&#x5F88;&#x7C21;&#x55AE;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E; <code>arch</code> &#x9019;&#x500B;&#x6307;&#x4EE4;&#x4F86;&#x5E6B;&#x6211;&#x5011;&#x8DF3;&#x5165; <code>x86_64</code> &#x7684;&#x4E16;&#x754C;&#xFF1A;</p>
<pre><code class="language-bash">$ which uname
/usr/bin/uname
$ file /usr/bin/uname
/usr/bin/uname: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
/usr/bin/uname (for architecture x86_64):	Mach-O 64-bit executable x86_64
/usr/bin/uname (for architecture arm64e):	Mach-O 64-bit executable arm64e
$ uname -u
arm64
$ arch -arch x86_64 uname -u
x86_64
$
</code></pre>
<p>&#x540C;&#x7406;&#xFF0C;&#x6211;&#x5011;&#x4E5F;&#x53EF;&#x4EE5;&#x9760; <code>arch</code> &#x6307;&#x4EE4;&#x4F86;&#x8B93;&#x6211;&#x5011;&#x6253;&#x958B;&#x4E00;&#x500B; x86_64 &#x7684; Shell&#xFF0C;&#x5728;&#x88E1;&#x9762;&#x904B;&#x4F5C;&#x7684;&#x7A0B;&#x5F0F;&#x5C31;&#x90FD;&#x6703;&#x4EE5; x86_64 &#x512A;&#x5148;&#x4E86;&#xFF1A;</p>
<pre><code class="language-bash">$ arch -arch x86_64 bash
[x86_64] $ uname -m
x86_64
$ arch -arch arm64e bash
[arm64e] $ uname -m
arm64
[arm64e] $
</code></pre>
<p>&#x96D6;&#x7136;&#x9019;&#x500B;&#x7BC4;&#x4F8B;&#x4E2D;&#x8868;&#x793A;&#x53EF;&#x4EE5;&#x5728; x86_64 &#x6A21;&#x5F0F;&#x4E0B;&#x518D;&#x8DF3;&#x56DE; arm64e &#x6A21;&#x5F0F;<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>&#xFF0C;&#x4F46;&#x5176;&#x5BE6;&#x9019;&#x4EF6;&#x4E8B;&#x60C5;&#x5728; 11.0.1 &#x7684;&#x6642;&#x5019;&#x9084;&#x662F;&#x4E0D;&#x884C;&#x7684;&#xFF0C;&#x6703;&#x5674;&#x51FA;&#x4E0D;&#x8A8D;&#x8B58;&#x7684; architecture &#x932F;&#x8AA4;&#xFF0C;&#x4F46;&#x5728; 11.1 &#x4E4B;&#x5F8C;&#x5C31;&#x53EF;&#x4EE5;&#x4E86;&#xFF01;</p>
<h3 id="%E9%80%8F%E9%81%8E-sysctl-%E5%8F%96%E5%BE%97%E7%9B%AE%E5%89%8D%E6%98%AF%E4%B8%8D%E6%98%AF%E5%9C%A8-rosetta-%E4%B8%AD%E9%81%8B%E4%BD%9C">&#x900F;&#x904E; sysctl &#x53D6;&#x5F97;&#x76EE;&#x524D;&#x662F;&#x4E0D;&#x662F;&#x5728; Rosetta &#x4E2D;&#x904B;&#x4F5C;</h3>
<p>&#x9019;&#x500B;&#x4E5F;&#x662F;&#x4E00;&#x500B;&#x5BE6;&#x7528;&#x7684;&#x5C0F;&#x6280;&#x5DE7;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x900F;&#x904E; sysctl &#x77AD;&#x89E3;&#x76EE;&#x524D;&#x7684;&#x74B0;&#x5883;&#x662F;&#x4E0D;&#x662F;&#x5728; Rosetta &#x4E2D;&#xFF1A;</p>
<pre><code class="language-bash">$ sysctl -n sysctl.proc_translated
0
$ arch -arch x86_64 sysctl -n sysctl.proc_translated
1
$
</code></pre>
<p>&#x5982;&#x679C; <code>sysctl.proc_translated</code> &#x7684;&#x503C;&#x662F; <code>1</code> &#x8868;&#x793A;&#x76EE;&#x524D;&#x6B63;&#x5728; Rosetta &#x4E2D;&#x57F7;&#x884C;&#x3002;</p>
<h2 id="ios-app-%E7%9B%B8%E9%97%9C">iOS App &#x76F8;&#x95DC;</h2>
<p>&#x9019;&#x88E1;&#x6703;&#x5217;&#x51FA;&#x4E00;&#x4E9B;&#x8207; iOS App &#x76F8;&#x95DC;&#x7684;&#x5C0F;&#x6280;&#x5DE7;&#xFF1A;</p>
<h3 id="%E5%AE%89%E8%A3%9D-ipa-%E5%BE%8C%E7%84%A1%E6%B3%95%E5%9F%B7%E8%A1%8C">&#x5B89;&#x88DD; ipa &#x5F8C;&#x7121;&#x6CD5;&#x57F7;&#x884C;</h3>
<p><img src="https://i.imgur.com/cFRSt2L.png" alt="&#x4F7F;&#x7528; M1 Mac &#x7684;&#x4E00;&#x4E9B;&#x5C0F;&#x6280;&#x5DE7;" loading="lazy"></p>
<p>&#x6709;&#x6642;&#x5019;&#x6703;&#x9047;&#x5230;&#x5B89;&#x88DD; .ipa &#x4E4B;&#x5F8C;&#xFF0C;macOS &#x537B;&#x963B;&#x6B62;&#x4F60;&#x57F7;&#x884C;&#x7684;&#x60C5;&#x6CC1;&#xFF0C;&#x9019;&#x6642;&#x5019;&#x6709;&#x53EF;&#x80FD;&#x662F;&#x56E0;&#x70BA;&#x9019;&#x500B; App &#x88AB;&#x4E0A;&#x4E86; <code>com.apple.quarantine</code> &#x9019;&#x500B;&#x5C6C;&#x6027;&#xFF0C;&#x6211;&#x5011;&#x53EA;&#x8981;&#x7528;&#x4E0B;&#x9762;&#x7684;&#x65B9;&#x5F0F;&#x5C31;&#x53EF;&#x4EE5;&#x89E3;&#x958B;&#x675F;&#x7E1B;&#xFF1A;</p>
<pre><code class="language-bash">$ sudo xattr -dr com.apple.quarantine &lt;Installed.app&gt;
</code></pre>
<p>&#x901A;&#x5E38;&#x9019;&#x500B;&#x5C6C;&#x6027;&#x4EE3;&#x8868;&#x7684;&#x662F;&#x4E0D;&#x5B89;&#x5168;&#x7684;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#xFF0C;&#x4F8B;&#x5982;&#x5F9E;&#x700F;&#x89BD;&#x5668;&#x4E0B;&#x8F09;&#x56DE;&#x4F86;&#x7684;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x5C31;&#x6703;&#x81EA;&#x52D5;&#x6253;&#x4E0A;&#x9019;&#x500B;&#x5C6C;&#x6027;&#xFF0C;&#x53EA;&#x662F;&#x4E0D;&#x77E5;&#x9053;&#x70BA;&#x4F55;&#x5F9E; ipa &#x5B89;&#x88DD;&#x7684; App &#x4E26;&#x4E0D;&#x6703;&#x63D0;&#x9192;&#x4F60;&#x662F;&#x5426;&#x5141;&#x8A31;&#x57F7;&#x884C;&#xFF0C;&#x800C;&#x662F;&#x76F4;&#x63A5;&#x62D2;&#x7D55;&#x4F60;&#x57F7;&#x884C;&#x3002;</p>
<h2 id="cli-%E7%9B%B8%E9%97%9C">CLI &#x76F8;&#x95DC;</h2>
<p>&#x9019;&#x88E1;&#x5217;&#x51FA;&#x4E00;&#x4E9B;&#x8DDF; CLI &#x6709;&#x95DC;&#x7684;&#x5C0F;&#x6280;&#x5DE7;&#xFF0C;&#x5982;&#x679C;&#x662F;&#x6709;&#x95DC;&#x5982;&#x4F55;&#x5728; CLI &#x57F7;&#x884C; Rosetta &#x7684;&#x8A71;&#x53EF;&#x4EE5;&#x5F80;&#x4E0A;&#x9762;&#x7684;&#x7BC0;&#x6B21;&#x770B;&#xFF1A;</p>
<h3 id="%E5%AE%89%E8%A3%9D-homebrew">&#x5B89;&#x88DD; Homebrew</h3>
<p>&#x9019;&#x597D;&#x50CF;&#x4E0D;&#x7BA1;&#x662F;&#x4E0D;&#x662F; M1 Mac &#x90FD;&#x6703;&#x7528;&#x5230;&#xFF0C;&#x4F46;&#x7531;&#x65BC; Homebrew &#x6563;&#x4F48;&#x7684;&#x57F7;&#x884C;&#x6A94;&#x90FD;&#x662F;&#x55AE;&#x4E00;&#x67B6;&#x69CB;&#x7684;&#xFF0C;&#x6240;&#x4EE5;&#x9019;&#x908A;&#x6703;&#x53E6;&#x5916;&#x5C55;&#x793A;&#x5982;&#x4F55;&#x5B89;&#x88DD; Intel &#x67B6;&#x69CB;&#x7684; Homebrew&#xFF08;&#x4EE5;&#x53D6;&#x5F97; Intel &#x67B6;&#x69CB;&#x7684;&#x57F7;&#x884C;&#x6A94;&#xFF09;&#x3002;</p>
<p>Apple Silicon &#x7248;&#x672C;&#x7684; Homebrew&#xFF0C;&#x6309;&#x7167;&#x539F;&#x5148;&#x7684;&#x5B89;&#x88DD;&#x65B9;&#x5F0F;&#x5C31;&#x53EF;&#x4EE5;&#x4E86;&#xFF1A;</p>
<pre><code class="language-bash">$ /bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&quot;
</code></pre>
<p>&#x518D;&#x4F86;&#x662F; Intel &#x67B6;&#x69CB;&#x7684; Homebrew&#xFF0C;&#x96D6;&#x7136; Homebrew &#x662F;&#x7528; Ruby &#x64B0;&#x5BEB;&#x800C;&#x6210;&#xFF0C;&#x5176;&#x5BE6;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x7528;&#x524D;&#x9762;&#x63D0;&#x5230;&#x7684; <code>arch</code> &#x4F86;&#x5207;&#x63DB;&#x81F3; Intel &#x67B6;&#x69CB;&#x57F7;&#x884C;&#xFF0C;&#x4F46;&#x6211;&#x662F;&#x5EFA;&#x8B70;&#x628A; Intel &#x67B6;&#x69CB;&#x7528;&#x7684; Homebrew &#x8DDF; Apple &#x67B6;&#x69CB;&#x7528;&#x7684; Homebrew &#x5206;&#x958B;&#xFF0C;&#x907F;&#x514D; Homebrew &#x641E;&#x4E0D;&#x6E05;&#x695A;&#x8DE8;&#x67B6;&#x69CB; library &#x4E4B;&#x9593;&#x7684;&#x76F8;&#x4F9D;&#x6027;&#x3002;</p>
<p>&#x6240;&#x4EE5;&#x6211;&#x5011;&#x9700;&#x8981;&#x7528;&#x66FF;&#x4EE3;&#x5B89;&#x88DD;<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup>&#x7684;&#x65B9;&#x5F0F;&#x628A; Homebrew &#x5B89;&#x88DD;&#x5230;&#x6307;&#x5B9A;&#x7684;&#x4F4D;&#x7F6E;&#xFF08;&#x9019;&#x88E1;&#x8209;&#x4F8B;&#x662F; <code>/opt/homebrew.x86_64</code>&#xFF09;&#xFF1A;</p>
<pre><code class="language-bash">$ mkdir -p /opt/homebrew.x86_64
$ curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C /opt/homebrew.x86_64
</code></pre>
<p>&#x63A5;&#x4E0B;&#x4F86;&#x6211;&#x6703;&#x5728;&#x6211;&#x7684; Terminal &#x4E2D;&#x8A2D;&#x5B9A;&#x5169;&#x500B; Profile&#xFF0C;&#x4E00;&#x500B;&#x662F; Apple &#x67B6;&#x69CB;&#x7684; Shell&#x3001;&#x53E6;&#x4E00;&#x500B;&#x662F; Intel &#x67B6;&#x69CB;&#x7684;&#xFF08;&#x4E00;&#x6A23;&#x7528; <code>arch</code> &#x95DC;&#x9032; Intel &#x6A21;&#x5F0F;&#xFF09;Shell&#xFF0C;&#x4E26;&#x4E14;&#x5728; shellrc &#x4E2D;&#x52A0;&#x5165;&#x74B0;&#x5883;&#x5075;&#x6E2C;&#x4F86;&#x5224;&#x65B7;&#x4F7F;&#x7528;&#x54EA;&#x500B; Homebrew&#xFF1A;</p>
<pre><code class="language-zsh"># ~/.zprofile

if [ &quot;$(sysctl -n sysctl.proc_translated)&quot; = &quot;1&quot; ]; then
	eval $(/opt/homebrew.x86_64/bin/brew shellenv)
else
	eval $(/opt/homebrew/bin/brew shellenv)
fi
</code></pre>
<pre><code class="language-fish"># ~/.config/fish/config.fish

set is_rosetta (sysctl -n sysctl.proc_translated)
if [ $is_rosetta = &apos;1&apos; ]
    set homebrew /opt/homebrew.x86_64/bin
else
    set homebrew /opt/homebrew/bin
end

set default_path /usr/local/bin /usr/bin /usr/sbin /bin /sbin
set -gx PATH $homebrew $default_path
</code></pre>
<p><a id="&#x96DC;&#x8A18;"></a></p>
<h2 id="%E9%9B%9C%E8%A8%98">&#x96DC;&#x8A18;</h2>
<p>&#x6700;&#x5F8C;&#x5C0F;&#x5C0F;&#x62B1;&#x6028;&#x4E00;&#x4E0B; macOS 11.0.1 &#x6839;&#x672C;&#x5C31;&#x662F;&#x9084;&#x6C92;&#x6709;&#x5B8C;&#x6210;&#x7684;&#x7248;&#x672C;&#x2026;&#x2026;<br>
Bug &#x6709;&#x5920;&#x591A;<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>&#xFF0C;&#x800C;&#x4E14;&#x9084;&#x6C92;&#x8FA6;&#x6CD5;&#x505A;&#x96D9;&#x5411;&#x8F49;&#x63DB;&#xFF08;&#x4EBA;&#x5BB6; Windows &lt;&gt; WSL &#x5C31;&#x53EF;&#x4EE5;&#x4E92;&#x76F8;&#x547C;&#x53EB;&#xFF09;&#xFF0C;&#x597D;&#x96AA; 11.1 &#x4E4B;&#x5F8C;&#x9019;&#x4E9B;&#x7F3A;&#x9EDE;&#x90FD;&#x6709;&#x88DC;&#x56DE;&#x4F86;&#x3002;<br>
&#x518D;&#x7528;&#x4E00;&#x9663;&#x5B50;&#x4E5F;&#x8A31;&#x9084;&#x6703;&#x518D;&#x589E;&#x52A0;&#x4E00;&#x4E9B;&#x6280;&#x5DE7;&#xFF0C;&#x4E0D;&#x904E;&#x57FA;&#x65BC;&#x6211;&#x9084;&#x5728;&#x8907;&#x7FD2; macOS&#xFF08;&#x7562;&#x7ADF;&#x6709;&#x597D;&#x591A;&#x5E74;&#x6C92;&#x7528; Mac &#x4E86;&#x2026;&#x2026;&#xFF09;&#xFF0C;&#x6240;&#x4EE5;&#x53EF;&#x80FD;&#x9700;&#x8981;&#x518D;&#x4E00;&#x4E0B;&#x4E0B;&#x624D;&#x6703;&#x66F4;&#x65B0;XD</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x500B;&#x4EBA;&#x731C;&#x6E2C;&#x662F; Architecture &#x7684;&#x7FFB;&#x8B6F;&#x5566;&#x2026;&#x2026; &#x8FD1;&#x5E74;&#x4F86;&#x860B;&#x679C;&#x5F88;&#x591A;&#x540D;&#x8A5E;&#x90FD;&#x6703;&#x523B;&#x610F;&#x627E;&#x4E00;&#x500B;&#x4E2D;&#x6587;&#x7FFB;&#x8B6F;&#x2026;&#x2026; &#x4EE5;&#x524D;&#x4E0D;&#x6703;&#x7684;&#x554A; QQ <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Rosetta 2 &#x53EF;&#x8B93;&#x914D;&#x5099; Apple &#x6676;&#x7247;&#x7684; Mac &#x4F7F;&#x7528;&#x5C08;&#x70BA;&#x914D;&#x5099; Intel &#x8655;&#x7406;&#x5668;&#x7684; Mac &#x6240;&#x958B;&#x767C;&#x7684; App&#x3002; &#x8A73;&#x898B; <a href="https://support.apple.com/zh-tw/HT211861?ref=blog.davy.tw">Apple &#x652F;&#x63F4;&#x9801;&#x9762;</a> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>&#x4EE5;&#x524D;&#x5F9E; PowerPC &#x67B6;&#x69CB;&#x8F49;&#x63DB;&#x81F3; Intel &#x67B6;&#x69CB;&#x6642;&#x860B;&#x679C;&#x5C31;&#x6709;&#x63D0;&#x51FA;&#x76F8;&#x540C;&#x7684;&#x89E3;&#x6C7A;&#x65B9;&#x6848;&#xFF0C;&#x4F7F;&#x5F97;&#x4E0D;&#x540C;&#x67B6;&#x69CB;&#x7684;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x53EF;&#x4EE5;&#x540C;&#x6642;&#x5B58;&#x5728;&#x65BC;&#x4E00;&#x500B;&#x57F7;&#x884C;&#x6A94;&#x4E2D;&#x3002;&#x8A73;&#x898B;<a href="https://en.wikipedia.org/wiki/Universal_binary?ref=blog.davy.tw">&#x7DAD;&#x57FA;&#x767E;&#x79D1;&#x7684;&#x3008;Universal Binary&#x3009;&#x689D;&#x76EE;</a>&#x3002; <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>&#x5728; <code>man arch</code> &#x4E2D;&#x6709;&#x5217;&#x51FA;&#x5E7E;&#x500B;&#x53EF;&#x4EE5;&#x4F7F;&#x7528;&#x7684;&#x6A21;&#x5F0F;&#xFF0C;&#x5305;&#x542B;&#xFF1A;<code>i386</code>, <code>x86_64</code>, <code>x86_64h</code>(Haswell), <code>arm64</code>, <code>arm64e</code>(Apple Silicon)&#x3002; <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p>&#x53C3;&#x8003; <a href="https://docs.brew.sh/Installation?ref=blog.davy.tw#untar-anywhere">Homebrew &#x5B89;&#x88DD;&#x8AAA;&#x660E;</a> <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p>&#x6709;&#x8208;&#x8DA3;&#x770B;&#x6211;&#x8E29;&#x5230;&#x4EC0;&#x9EBC;&#x96F7;&#x7684;&#x53EF;&#x4EE5;&#x770B;&#x770B;&#x6211;&#x767C;&#x7684;<a href="https://twitter.com/david50407/status/1352252210827051010?ref=blog.davy.tw">&#x5EE2;&#x63A8;</a>(ry <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[在 Ubuntu 裡面啓用 cgroups v2]]></title><description><![CDATA[因為最近跳了 Podman 的坑，所以就想說順便玩玩 rootless container 好了，結果發現如果要用 rootless container 的話，Podman 在 cgroups v2 裡面才可以做各種資源限制，但 Ubuntu 預設只使用了 cgroups v1，所以下面就來看看要怎麼把它切到 v2 ……]]></description><link>https://blog.davy.tw/posts/enable-cgroups-v2-in-ubuntu/</link><guid isPermaLink="false">5fe4a2c18b52a70001c22760</guid><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Thu, 24 Dec 2020 16:03:16 GMT</pubDate><content:encoded><![CDATA[<p>&#x56E0;&#x70BA;&#x6700;&#x8FD1;&#x8DF3;&#x4E86; Podman<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> &#x7684;&#x5751;&#xFF0C;&#x6240;&#x4EE5;&#x5C31;&#x60F3;&#x8AAA;&#x9806;&#x4FBF;&#x73A9;&#x73A9; rootless container &#x597D;&#x4E86;&#xFF0C;&#x7D50;&#x679C;&#x767C;&#x73FE;&#x5982;&#x679C;&#x8981;&#x7528; rootless container &#x7684;&#x8A71;&#xFF0C;Podman &#x5728; cgroups v2 &#x88E1;&#x9762;&#x624D;&#x53EF;&#x4EE5;&#x505A;&#x5404;&#x7A2E;&#x8CC7;&#x6E90;&#x9650;&#x5236;&#xFF0C;&#x4F46; Ubuntu &#x9810;&#x8A2D;&#x53EA;&#x4F7F;&#x7528;&#x4E86; cgroups v1&#xFF0C;&#x6240;&#x4EE5;&#x4E0B;&#x9762;&#x5C31;&#x4F86;&#x770B;&#x770B;&#x8981;&#x600E;&#x9EBC;&#x628A;&#x5B83;&#x5207;&#x5230; v2 &#x56C9;&#x3002;</p>
<h2 id="tldr">TL;DR</h2>
<pre><code class="language-bash">#!/bin/bash

echo &apos;GRUB_CMDLINE_LINUX_DEFAULT=&quot;${GRUB_CMDLINE_LINUX_DEFAULT} systemd.unified_cgroup_hierarchy=1&quot;&apos; | sudo tee /etc/default/grub.d/70-cgroup-unified.cfg
sudo update-grub

</code></pre>
<h2 id="kernel-parameters">Kernel parameters</h2>
<p>&#x60F3;&#x8981;&#x5728; Systemd enabled Linux &#x88E1;&#x9762;&#x5553;&#x7528; cgroups v2 &#x7684;&#x8A71;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x5728; kernel parameters &#x88E1;&#x9762;&#x52A0;&#x4E0A; <code>systemd.unified_cgroup_hierarchy=1</code><sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x5373;&#x53EF;&#x5728;&#x958B;&#x6A5F;&#x5F8C;&#x4F7F;&#x7528; cgroups v2&#x3002;</p>
<h3 id="grub">Grub</h3>
<p>&#x96D6;&#x7136;&#x5728;&#x958B;&#x6A5F;&#x7684;&#x6642;&#x5019;&#x53EF;&#x4EE5;&#x624B;&#x52D5;&#x4FEE;&#x6539; parameters&#xFF0C;&#x4F46;&#x7E3D;&#x4E0D;&#x53EF;&#x80FD;&#x6BCF;&#x6B21;&#x958B;&#x6A5F;&#x7684;&#x6642;&#x5019;&#x90FD;&#x624B;&#x52D5;&#x8ABF;&#x6574;&#xFF0C;&#x6240;&#x4EE5;&#x6211;&#x5011;&#x8981;&#x9760;&#x4FEE;&#x6539; grub &#x958B;&#x6A5F;&#x9078;&#x55AE;&#x4F86;&#x5E6B;&#x6211;&#x5011;&#x89E3;&#x6C7A;&#x9019;&#x500B;&#x554F;&#x984C;&#x3002;</p>
<p>&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x5728; <code>/etc/default/grub</code> &#x88E1;&#x9762;&#x76F4;&#x63A5;&#x6DFB;&#x52A0; <code>GRUB_CMDLINE_LINUX_DEFAULT=&quot;systemd.unified_cgroup_hierarchy=1&quot;</code> &#x6216;&#x662F;&#x5728; <code>/etc/default/grub.d/</code> &#x4E0B;&#x9762;&#x65B0;&#x589E;&#x4E00;&#x500B;&#x6A94;&#x6848;&#x4F86;&#x8F09;&#x5165;&#x8A2D;&#x5B9A;&#xFF0C;&#x6211;&#x81EA;&#x5DF1;&#x6703;&#x9078;&#x64C7;&#x5F8C;&#x8005;<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>&#xFF0C;&#x907F;&#x514D;&#x88AB;&#x5176;&#x4ED6;&#x8A2D;&#x5B9A;&#x6A94;&#x8986;&#x84CB;&#xFF08;&#x4F8B;&#x5982;&#xFF1A; <code>50-curtin-settings.cfg</code> &#x6703;&#x8986;&#x5BEB; <code>GRUB_CMDLINE_LINUX_DEFAULT</code>&#xFF09;&#xFF1A;</p>
<pre><code class="language-bash"># /etc/default/grub.d/70-cgroup-unified.cfg
GRUB_CMDLINE_LINUX_DEFAULT=&quot;${GRUB_CMDLINE_LINUX_DEFAULT} systemd.unified_cgroup_hierarchy=1&quot;
</code></pre>
<p>&#x4FEE;&#x6539;&#x5B8C;&#x7562;&#x5F8C;&#x57F7;&#x884C; <code>sudo update-grub</code> &#x5373;&#x53EF;&#x5957;&#x7528;&#x6211;&#x5011;&#x525B;&#x525B;&#x65B0;&#x589E;&#x7684;&#x8A2D;&#x5B9A;&#xFF0C;&#x4EA6;&#x53EF;&#x5F9E; <code>/boot/grub/grub.cfg</code> &#x6AA2;&#x67E5;&#x8A2D;&#x5B9A;&#x662F;&#x5426;&#x6709;&#x8AA4;&#xFF0C;&#x90FD;&#x6C92;&#x554F;&#x984C;&#x5F8C;&#x5C31;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x91CD;&#x958B;&#x6A5F;&#x4E86;&#xFF01;</p>
<h3 id="%E6%AA%A2%E6%9F%A5%E7%B5%90%E6%9E%9C">&#x6AA2;&#x67E5;&#x7D50;&#x679C;</h3>
<p>&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x5728;&#x91CD;&#x958B;&#x6A5F;&#x4E4B;&#x5F8C;&#x770B;&#x770B;&#x7CFB;&#x7D71;&#x662F;&#x4E0D;&#x662F;&#x771F;&#x7684;&#x6709;&#x628A; cgroups v2 &#x5553;&#x7528;&#xFF0C;&#x53EF;&#x4EE5;&#x5F9E; mount list &#x6AA2;&#x67E5;&#xFF1A;</p>
<pre><code class="language-sh">$ mount | grep cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)
</code></pre>
<p>&#x4E5F;&#x53EF;&#x4EE5;&#x624B;&#x52D5; mount &#x770B;&#x770B; cgroups2&#xFF1A;</p>
<pre><code class="language-sh">$ sudo mkdir -p /test-cgroups2
$ sudo mount -t cgroup2 none /test-cgroups2
$ ls /test-cgroups2
cgroup.controllers  cgroup.max.descendants  cgroup.stat             cgroup.threads
cgroup.max.depth    cgroup.procs            cgroup.subtree_control  ...
$ sudo umount /test-cgroups2
$ sudo rmdir /test-cgroups2
</code></pre>
<p>&#x5982;&#x679C;&#x53EF;&#x4EE5;&#x6210;&#x529F;&#x5B58;&#x53D6; cgroups2 &#x7684;&#x8CC7;&#x6E90;&#xFF0C;&#x57FA;&#x672C;&#x4E0A;&#x5C31;&#x662F;&#x6210;&#x529F;&#x4E86;&#xFF01;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://podman.io/?ref=blog.davy.tw">Podman</a>, a Pod Manager tool. <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://wiki.archlinux.org/index.php/Cgroups?ref=blog.davy.tw#Switching_to_cgroups_v2">cgroups - ArchWiki</a> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>&#x95DC;&#x65BC; <code>/etc/default/grub.d</code> &#x662F;&#x5982;&#x4F55;&#x88AB;&#x8F09;&#x5165;&#x7684;&#xFF0C;&#x53EF;&#x4EE5;&#x53C3;&#x8003; <code>/usr/sbin/grub-mkconfig</code> &#x88E1;&#x9762;&#x7684;&#x5BE6;&#x4F5C; <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[如何升級 EoL 的 Ubuntu 版本]]></title><description><![CDATA[最近有從 Ubuntu 18.10 升級的需求，但因為 18.10 早就在 2019/07/18 EoL 了，因此沒辦法直接使用 `do-release-upgrade` 升級，這個時候該怎麼辦呢？……]]></description><link>https://blog.davy.tw/posts/howto-upgrade-from-eol-ubuntu/</link><guid isPermaLink="false">5fd847578b52a70001c22687</guid><category><![CDATA[Ubuntu]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Tue, 15 Dec 2020 06:00:36 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x6700;&#x8FD1;&#x6709;&#x5F9E; Ubuntu 18.10 &#x5347;&#x7D1A;&#x7684;&#x9700;&#x6C42;&#xFF0C;&#x4F46;&#x56E0;&#x70BA; 18.10 &#x65E9;&#x5C31;&#x5728; 2019/07/18 EoL &#x4E86;&#xFF0C;&#x56E0;&#x6B64;&#x6C92;&#x8FA6;&#x6CD5;&#x76F4;&#x63A5;&#x4F7F;&#x7528; <code>do-release-upgrade</code> &#x5347;&#x7D1A;&#xFF0C;&#x9019;&#x500B;&#x6642;&#x5019;&#x8A72;&#x600E;&#x9EBC;&#x8FA6;&#x5462;&#xFF1F;</p>
<h2 id="tldr">TL;DR</h2>
<ul>
<li>&#x5982;&#x679C;&#x9084;&#x5728; Lifespan &#x7684;&#x7248;&#x672C;&#xFF1A;&#x76F4;&#x63A5; <code>do-release-upgrade [-d]</code></li>
<li>&#x5982;&#x679C;&#x5DF2;&#x7D93; EoL &#x7684;&#x7248;&#x672C;&#xFF1A;
<ul>
<li>&#x9078;&#x64C7;&#x4E0B;&#x4E00;&#x500B;&#x7248;&#x672C;
<ul>
<li>LTS&#xFF1A;&#x6700;&#x8FD1;&#x7684; LTS &#xFF08;<code>16.04 xenial</code> -&gt; <code>18.04 bionic</code>&#xFF09;</li>
<li>&#x975E; LTS&#xFF1A;&#x6700;&#x8FD1;&#x7684;&#x7248;&#x672C; &#xFF08;<code>18.10 cosmic</code> -&gt; <code>19.04 disco</code>&#xFF09;</li>
</ul>
</li>
</ul>
<pre><code class="language-sh">#!/bin/bash
set -euo pipefail

NEXT_CODE=&apos;disco&apos; # &#x4E0B;&#x4E00;&#x500B;&#x7248;&#x672C;&#x7684; codename

# &#x628A; apt &#x6E90;&#x5207;&#x5230; `http://old-releases.ubuntu.com/ubuntu/`
sudo sed -i -re &apos;s/([a-z]{2}\.)?archive.ubuntu.com|security.ubuntu.com/old-releases.ubuntu.com/g&apos; /etc/apt/sources.list
sudo apt update
sudo apt upgrade

pushd `mktemp -d`
curl http://old-releases.ubuntu.com/ubuntu/dists/${NEXT_CODE}-updates/main/dist-upgrader-all/current/${NEXT_CODE}.tar.gz | tar -zxf -
sudo python3 ./dist-upgrade.py
</code></pre>
</li>
</ul>
<h2 id="doreleaseupgrade">&#x53EF;&#x4EE5;&#x4F7F;&#x7528; <code>do-release-upgrade</code> &#x7684;&#x5834;&#x666F;</h2>
<p>Ubuntu &#x63D0;&#x4F9B; <code>do-release-upgrade</code><sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> &#x65B9;&#x4FBF;&#x4F7F;&#x7528;&#x8005;&#x66F4;&#x65B0;&#x5230;<strong>&#x6700;&#x65B0;&#x7684;</strong>&#x767C;&#x884C;&#x7248;&#x672C;&#xFF0C;&#x4F46;&#x5176;&#x66F4;&#x65B0;&#x8DEF;&#x7DDA;&#x662F;&#x6709;&#x9650;&#x5236;&#x7684;&#x3002;<br>
&#x4E00;&#x822C;&#x4F86;&#x8AAA; LTS &#x53EF;&#x4EE5;&#x5F9E;&#x4E0A;&#x4E00;&#x500B; LTS &#x6216;&#x666E;&#x901A;&#x7248;&#x672C;&#x66F4;&#x65B0;&#xFF0C;&#x800C;&#x666E;&#x901A;&#x7248;&#x672C;&#x53EA;&#x80FD;&#x5F9E;&#x4E0A;&#x4E00;&#x500B;&#x7248;&#x672C;&#x66F4;&#x65B0;&#xFF0C;&#x4F8B;&#x5982; <code>20.04</code> &#x53EF;&#x4EE5;&#x5F9E; <code>18.04</code> &#x8DDF; <code>19.10</code> &#x66F4;&#x65B0;&#x4E0A;&#x53BB;&#xFF0C;&#x4F46; <code>19.04</code> &#x53EA;&#x80FD;&#x5F9E; <code>18.10</code> &#x66F4;&#x65B0;&#xFF0C;&#x66F4;&#x591A;&#x8CC7;&#x8A0A;&#x53EF;&#x4EE5;&#x53C3;&#x8003; Ubuntu wiki &#x7684;&#x7248;&#x672C;&#x5347;&#x7D1A;&#x8AAA;&#x660E;<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>&#x3002;</p>
<p><code>do-release-upgrade</code> &#x6C7A;&#x5B9A;&#x4E0B;&#x4E00;&#x500B;&#x7248;&#x672C;&#x7684;&#x65B9;&#x5F0F;&#x53EF;&#x4EE5;&#x5F9E; <code>/etc/update-manager/release-upgrades</code> &#x4FEE;&#x6539;&#xFF0C;&#x53EF;&#x4EE5;&#x6307;&#x5B9A;&#x5230;&#x6700;&#x65B0;&#x666E;&#x901A;&#x7248;&#x672C;&#x9084;&#x662F;&#x6700;&#x65B0; LTS &#x7248;&#x672C;&#x3002;<br>
&#x5982;&#x679C;&#x76EE;&#x524D;&#x4F7F;&#x7528;&#x7684;&#x7248;&#x672C;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x66F4;&#x65B0;&#x5230;&#x6700;&#x65B0;&#x7684;&#x7248;&#x672C;&#x7684;&#x8A71;&#x90A3;&#x5C31;&#x76F4;&#x63A5;&#x7528; <code>do-release-upgrade [-d]</code> &#x5347;&#x7D1A;&#x5C31;&#x53EF;&#x4EE5;&#x4E86;&#x3002;</p>
<h2 id="doreleaseupgrade">&#x7121;&#x6CD5;&#x4F7F;&#x7528; <code>do-release-upgrade</code> &#x7684;&#x5834;&#x666F;</h2>
<p>&#x5982;&#x679C;&#x76EE;&#x524D;&#x7684;&#x7248;&#x672C;&#x5DF2;&#x7D93;&#x4E0D;&#x9069;&#x7528; <code>do-release-upgrade</code> &#x5347;&#x7D1A;&#x5230;&#x6700;&#x65B0;&#x7248;&#x672C;&#x6216;&#x4E0D;&#x6253;&#x7B97;&#x4F7F;&#x7528;&#x7684;&#x8A71;&#xFF0C;&#x53EF;&#x4EE5;&#x8003;&#x616E;&#x5F9E;&#x4E0B;&#x4E00;&#x500B;&#x7248;&#x672C;&#x7684;&#x8EDF;&#x9AD4;&#x6E90;&#x4E2D;&#x4E0B;&#x8F09;&#x5347;&#x7D1A;&#x5DE5;&#x5177;&#xFF1A;&#xFF08;&#x628A; <code>${NEXT_CODE}</code> &#x63DB;&#x6210;&#x4E0B;&#x4E00;&#x500B;&#x7248;&#x672C;&#x7684; codename&#xFF09;</p>
<pre><code class="language-txt"># &#x9084;&#x5728; Lifespan &#x7684;&#x7248;&#x672C;
http://archive.ubuntu.com/ubuntu/dists/${NEXT_CODE}-updates/main/dist-upgrader-all/current/${NEXT_CODE}.tar.gz
# &#x5DF2;&#x7D93; EoL &#x7684;&#x7248;&#x672C;
http://old-releases.ubuntu.com/ubuntu/dists/${NEXT_CODE}-updates/main/dist-upgrader-all/current/${NEXT_CODE}.tar.gz
</code></pre>
<p>&#x4E0B;&#x8F09;&#x56DE;&#x4F86;&#x4E4B;&#x5F8C;&#x53EF;&#x4EE5;&#x7528; <code>tar -zxf</code> &#x89E3;&#x58D3;&#x7E2E;&#xFF0C;&#x7136;&#x5F8C;&#x57F7;&#x884C; <code>sudo python3 ./dist-upgrade.py</code> &#x5C31;&#x53EF;&#x4EE5;&#x9032;&#x884C;&#x66F4;&#x65B0;&#x3002;</p>
<h2 id="eolaptupdate">EoL &#x7248;&#x672C;&#x7121;&#x6CD5; apt update &#x7684;&#x89E3;&#x6CD5;</h2>
<p>&#x5C0D;&#x65BC;&#x5DF2;&#x7D93; EoL &#x7684;&#x7248;&#x672C;&#xFF0C;Ubuntu &#x6703;&#x5C07;&#x5176;&#x8EDF;&#x9AD4;&#x6E90;&#x79FB;&#x52D5;&#x5230; <code>http://old-releases.ubuntu.com/ubuntu</code><sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> &#x4F86;&#x4FDD;&#x5B58;&#xFF0C;&#x5927;&#x5BB6;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x628A;&#x6E90;&#x5207;&#x5230;&#x9019;&#x908A;&#x7E7C;&#x7E8C;&#x4F7F;&#x7528;&#xFF0C;&#x4F46;&#x56E0;&#x70BA;&#x5DF2;&#x7D93; EoL &#x4E86;&#x7684;&#x95DC;&#x4FC2;&#xFF0C;&#x9084;&#x662F;&#x5EFA;&#x8B70;&#x8D95;&#x5FEB;&#x5347;&#x7D1A;&#x767C;&#x884C;&#x7248;&#x5427; XDDD</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x5927;&#x90E8;&#x5206;&#x60C5;&#x6CC1;&#x4E0B;&#x6703;&#x9810;&#x8F09;&#xFF0C;&#x6216;&#x662F;&#x53EF;&#x4EE5; <code>apt install update-manager-core</code> &#x53D6;&#x5F97; <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://help.ubuntu.com/community/DiscoUpgrades?ref=blog.davy.tw">19.04 Disco &#x53EF;&#x4EE5;&#x5F9E; 18.10 &#x5347;&#x7D1A;</a>&#xFF1B;&#x800C; <a href="https://help.ubuntu.com/community/FocalUpgrades?ref=blog.davy.tw">20.04 focal &#x5247;&#x53EF;&#x4EE5;&#x5F9E; 19.10/18.04 LTS &#x5347;&#x7D1A;</a> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p><a href="http://old-releases.ubuntu.com/releases/?ref=blog.davy.tw">Old Ubuntu Releases</a> <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[在 Vue.js 3 中取得 Listeners]]></title><description><![CDATA[由於 $listeners 在 Vue.js 3 中已經被移除了，如果要在 Component 中取用 Listeners 的話，就需要一點技巧了，我們這邊就分成兩個部分來討論。
TL;DR 想 inherit 到 root 的事件：從 $attrs 拿 想註冊的事件：以 onCamelCase 的名稱註冊到 props 中]]></description><link>https://blog.davy.tw/posts/access-listeners-in-vue3-components/</link><guid isPermaLink="false">5fca87268b52a70001c225a1</guid><category><![CDATA[Vue.js]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Fri, 04 Dec 2020 19:52:20 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x7531;&#x65BC; <code>$listeners</code> &#x5728; Vue.js 3 &#x4E2D;&#x5DF2;&#x7D93;&#x88AB;&#x79FB;&#x9664;&#x4E86;<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>&#xFF0C;&#x5982;&#x679C;&#x8981;&#x5728; Component &#x4E2D;&#x53D6;&#x7528; Listeners &#x7684;&#x8A71;&#xFF0C;&#x5C31;&#x9700;&#x8981;&#x4E00;&#x9EDE;&#x6280;&#x5DE7;&#x4E86;&#xFF0C;&#x6211;&#x5011;&#x9019;&#x908A;&#x5C31;&#x5206;&#x6210;&#x5169;&#x500B;&#x90E8;&#x5206;&#x4F86;&#x8A0E;&#x8AD6;&#x3002;</p>
<h3 id="tldr">TL;DR</h3>
<ul>
<li>&#x60F3; inherit &#x5230; root &#x7684;&#x4E8B;&#x4EF6;&#xFF1A;&#x5F9E; <code>$attrs</code> &#x62FF;</li>
<li>&#x60F3;&#x8A3B;&#x518A;&#x7684;&#x4E8B;&#x4EF6;&#xFF1A;&#x4EE5; <code>onCamelCase</code> &#x7684;&#x540D;&#x7A31;&#x8A3B;&#x518A;&#x5230; <code>props</code> &#x4E2D;</li>
</ul>
<h2 id="emitsattrs">&#x672A;&#x8A3B;&#x518A; emits &#x7684;&#x4E8B;&#x4EF6;&#xFF1A;&#x5F9E; $attrs &#x53D6;&#x7528;</h2>
<p>&#x4F9D;&#x7167; Vue.js 3 &#x7684;&#x8AAA;&#x660E;&#x4F86;&#x770B;&#xFF0C;<code>$listeners</code> &#x8DDF; <code>$attrs</code> &#x5408;&#x4F75;&#x4E86;&#xFF0C;&#x4EE5;&#x524D;&#x9700;&#x8981;&#x900F;&#x904E; <code>v-bind=&quot;$attrs&quot; v-on=&quot;$listeners&quot;</code> &#x4F86;&#x624B;&#x52D5;&#x628A;&#x5C6C;&#x6027;&#x53CA;&#x76E3;&#x807D;&#x5668;&#x50B3;&#x905E;&#x5230;&#x6307;&#x5B9A;&#x7684; DOM &#x4E0A;&#xFF0C;&#x800C;&#x73FE;&#x5728;&#x53EA;&#x9700;&#x8981;&#x4E00;&#x500B; <code>v-bind=&quot;$attrs&quot;</code> &#x5C31;&#x53EF;&#x4EE5;&#x641E;&#x5B9A;&#x4E86;&#x3002;</p>
<p>&#x56E0;&#x6B64;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x5F9E; <code>$attrs</code> &#x4E2D;&#x4F86;&#x53D6;&#x5F97;&#x60F3;&#x8981;&#x7684; listener&#xFF1A;</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;label&gt;
    &lt;input type=&quot;text&quot; v-bind=&quot;$attrs&quot; /&gt;
  &lt;/label&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  inheritAttrs: false,
  setup(props, { attrs }) {
    console.log(attrs) // =&gt; { onClick: () =&gt; {} }
  },
}
&lt;/script&gt;
</code></pre>
<h2 id="emitsprops">&#x5DF2;&#x8A3B;&#x518A; emits &#x7684;&#x4E8B;&#x4EF6;&#xFF1A;&#x6539;&#x7528; props &#x8A3B;&#x518A;</h2>
<p>&#x5C0D;&#x65BC;&#x9700;&#x8981;&#x8A3B;&#x518A;&#x5728; <code>emits</code> &#x7684;&#x4E8B;&#x4EF6;&#xFF08;&#x5982;&#x679C; <code>$emit()</code> &#x6642;&#x6240;&#x767C;&#x751F;&#x7684;&#x4E8B;&#x4EF6;&#x6C92;&#x6709;&#x88AB;&#x8A3B;&#x518A;&#x5230; <code>emits</code> &#x7684;&#x8A71;&#xFF0C;Vue.js 3 &#x6703;&#x5728;&#x767C;&#x751F;&#x4E8B;&#x4EF6;&#x7684;&#x6642;&#x5019;&#x767C;&#x51FA;&#x8B66;&#x544A;&#xFF09;&#xFF0C;&#x9019;&#x6642;&#x4E0A;&#x9762;&#x7684;&#x65B9;&#x5F0F;&#x5C31;&#x4E0D;&#x7BA1;&#x7528;&#x4E86;&#x2026;&#x2026;</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;label&gt;
    &lt;input type=&quot;text&quot; v-bind=&quot;$attrs&quot; /&gt;
  &lt;/label&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  inheritAttrs: false,
  emits: [&apos;click&apos;],
  setup(props, { attrs }) {
    console.log(attrs) // =&gt; {}
  },
}
&lt;/script&gt;
</code></pre>
<p>&#x9019;&#x500B;&#x6642;&#x5019;&#x8A72;&#x600E;&#x9EBC;&#x8FA6;&#x5462;&#xFF1F; &#x7576;&#x7136;&#x662F;&#x5148;&#x770B;&#x4E00;&#x4E0B;&#x70BA;&#x4EC0;&#x9EBC; Vue.js &#x6703;&#x6709;&#x5982;&#x6B64;&#x7684;&#x5DEE;&#x5225;&#x5566;&#xFF0C;&#x9996;&#x5148;&#x6211;&#x5011;&#x7D93;&#x6B77;&#x5343;&#x8F9B;&#x842C;&#x82E6; trace &#x5230;&#x4E86;<a href="https://github.com/vuejs/vue-next/blob/0af8c8d972392fe929185b13c94fc7a924c8be0f/packages/runtime-core/src/componentProps.ts?ref=blog.davy.tw#L268">&#x9019;&#x88E1;</a>&#xFF08;componentProps.ts#setFullProps()&#xFF09;&#xFF1A;</p>
<pre><code class="language-javascript">function setFullProps(instance, rawProps, props, attrs) {
    const [options, needCastKeys] = instance.propsOptions;
    if (rawProps) {
        for (const key in rawProps) {
            const value = rawProps[key];
            // ...
            
            // prop option names are camelized during normalization, so to support
            // kebab -&gt; camel conversion here we need to camelize the key.
            let camelKey;
            if (options &amp;&amp; shared.hasOwn(options, (camelKey = shared.camelize(key)))) {
                props[camelKey] = value;
            }
            else if (!isEmitListener(instance.emitsOptions, key)) {
                // Any non-declared (either as a prop or an emitted event) props are put
                // into a separate `attrs` object for spreading. Make sure to preserve
                // original key casing
                attrs[key] = value;
            }
        }
    }
    // ...
}
</code></pre>
<p>&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x9019;&#x88E1;&#x7684;&#x908F;&#x8F2F;&#x662F;&#xFF1A;</p>
<ol>
<li>&#x5982;&#x679C;&#x9019;&#x500B; prop key &#x7684; camelCase &#x7248;&#x672C;&#x662F;&#x5408;&#x6CD5;&#x7684; <code>props</code> &#x7684;&#x8A71;&#xFF0C;&#x90A3;&#x5C31;&#x585E;&#x9032; <code>props[camelKey]</code> &#x88E1;&#x9762;</li>
<li>&#x5982;&#x679C;&#x9019;&#x500B; prop key <strong>&#x4E0D;&#x662F;</strong>&#x4E00;&#x500B;&#x8A3B;&#x518A;&#x5728; <code>emits</code> &#x7684;&#x5C6C;&#x6027;&#x7684;&#x8A71;&#xFF0C;&#x90A3;&#x5C31;&#x585E;&#x9032; <code>attrs[key]</code> &#x88E1;&#x9762;</li>
</ol>
<p>&#x9019;&#x88E1;&#x53EF;&#x4EE5;&#x5F88;&#x7C21;&#x55AE;&#x7684;&#x770B;&#x51FA;&#xFF0C;&#x5982;&#x679C;&#x8A3B;&#x518A;&#x5230; <code>emits</code> &#x7684;&#x4E8B;&#x4EF6;&#xFF0C;&#x5176; <code>onXXXXX</code> &#x662F;&#x65E2;&#x4E0D;&#x6703;&#x653E;&#x9032; <code>props</code> &#x4E5F;&#x4E0D;&#x6703;&#x653E;&#x9032; <code>attrs</code> &#x7684;&#xFF0C;&#x8DDF;&#x6211;&#x5011;&#x89C0;&#x5BDF;&#x5230;&#x7684;&#x73FE;&#x8C61;&#x543B;&#x5408;&#x3002;</p>
<p>&#x90A3;&#x6211;&#x5011;&#x8981;&#x600E;&#x9EBC;&#x8655;&#x7406;&#x5462;&#xFF1F; &#x5F88;&#x7C21;&#x55AE;&#xFF0C;&#x628A;&#x539F;&#x672C;&#x8A3B;&#x518A;&#x5728; <code>emits</code> &#x88E1;&#x9762;&#x7684;&#x4E8B;&#x4EF6;&#xFF0C;&#x6539;&#x8A3B;&#x518A;&#x5230; <code>props</code> &#x5C31;&#x597D;&#x5566;&#xFF0C;&#x9019;&#x9EBC;&#x4E00;&#x4F86;&#x6211;&#x5011;&#x4E0D;&#x5C31;&#x53EF;&#x4EE5;&#x5728; <code>props</code> &#x88E1;&#x9762;&#x53D6;&#x7528;&#x76E3;&#x807D;&#x5668;&#x4E86;&#x55CE;&#xFF1F;</p>
<p>&#x7576;&#x7136;&#xFF0C;&#x6709;&#x7814;&#x7A76;&#x7CBE;&#x795E;&#x7684;&#x6211;&#x5011;&#x9084;&#x662F;&#x8981;&#x4F86;&#x770B;&#x4E00;&#x4E0B; Vue.js &#x662F;&#x600E;&#x9EBC;&#x8655;&#x7406; <code>emit</code> &#x4E8B;&#x4EF6;&#x7684;&#xFF0C;&#x8981;&#x662F;&#x6211;&#x5011;&#x8A3B;&#x518A;&#x5230; <code>props</code> &#x7D50;&#x679C;&#x5C0E;&#x81F4;&#x4E8B;&#x4EF6;&#x4E0D;&#x80FD;&#x88AB;&#x76E3;&#x807D;&#x5C31;&#x597D;&#x7B11;&#x4E86;&#xFF0C;&#x6240;&#x4EE5;&#x6211;&#x5011;&#x4F86;&#x770B;&#x4E00;&#x4E0B; <code>emit</code> <a href="https://github.com/vuejs/vue-next/blob/0af8c8d972392fe929185b13c94fc7a924c8be0f/packages/runtime-core/src/componentEmits.ts?ref=blog.davy.tw#L46">&#x662F;&#x600E;&#x9EBC;&#x505A;&#x7684;</a>&#x56C9;&#xFF08;componentEmits.ts#emit()&#xFF09;&#xFF1A;</p>
<pre><code class="language-javascript">function emit(instance, event, ...rawArgs) {
    const props = instance.vnode.props || shared.EMPTY_OBJ;
    if (__DEV__) {
        const { emitsOptions, propsOptions: [propsOptions] } = instance;
        if (emitsOptions) {
            if (!(event in emitsOptions)) {
                if (!propsOptions || !(shared.toHandlerKey(event) in propsOptions)) {
                    warn(`Component emitted event &quot;${event}&quot; but it is neither declared in ` +
                        `the emits option nor as an &quot;${shared.toHandlerKey(event)}&quot; prop.`);
                }
            }
            else {
                const validator = emitsOptions[event];
                if (shared.isFunction(validator)) {
                    const isValid = validator(...rawArgs);
                    if (!isValid) {
                        warn(`Invalid event arguments: event validation failed for event &quot;${event}&quot;.`);
                    }
                }
            }
        }
    }
    // ...
    
    // convert handler name to camelCase. See issue #2249
    let handlerName = shared.toHandlerKey(shared.camelize(event));
    let handler = props[handlerName];
    // for v-model update:xxx events, also trigger kebab-case equivalent
    // for props passed via kebab-case
    if (!handler &amp;&amp; isModelListener) {
        handlerName = shared.toHandlerKey(shared.hyphenate(event));
        handler = props[handlerName];
    }
    if (handler) {
        callWithAsyncErrorHandling(handler, instance, ErrorCodes.COMPONENT_EVENT_HANDLER, args);
    }
    // ...
}
</code></pre>
<p>&#x9019;&#x908A;&#x6211;&#x523B;&#x610F;&#x5730;&#x628A; <code>if (__DEV__)</code> &#x6BB5;&#x4FDD;&#x7559;&#xFF0C;&#x5176;&#x5BE6;&#x770B;&#x5230;&#x88E1;&#x9762;&#x7684;&#x6558;&#x8FF0;&#x5927;&#x6982;&#x5C31;&#x53EF;&#x4EE5;&#x7406;&#x89E3;&#x4E86;&#xFF0C;Vue.js &#x5728;&#x8655;&#x7406; <code>emit()/$emit()</code> &#x7684;&#x6642;&#x5019;&#xFF0C;&#x6703;&#x5148;&#x5224;&#x65B7;&#x9019;&#x500B;&#x4E8B;&#x4EF6;&#x662F;&#x4E0D;&#x662F;&#x6709;&#x88AB;&#x8A3B;&#x518A;&#x5728; <code>emits</code> <strong>&#x6216;&#x4EE5; <code>onXXXXX</code><sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x7684;&#x5F62;&#x5F0F;&#x8A3B;&#x518A;&#x5728; <code>props</code></strong> &#x88E1;&#xFF0C;&#x56E0;&#x6B64;&#x6211;&#x5011;&#x4EE5; <code>onXXXXX</code> &#x7684;&#x5F62;&#x5F0F;&#x8A3B;&#x518A;&#x5728; <code>props</code> &#x4E2D;&#x9084;&#x662F;&#x7B26;&#x5408;&#x8A2D;&#x8A08;&#x7684;&#x3002; &#x4E26;&#x4E14;&#xFF0C;Vue.js &#x5728;&#x8655;&#x7406; listener &#x7684;&#x6642;&#x5019;&#xFF0C;&#x4E5F;&#x9084;&#x662F;&#x56DE;&#x982D;&#x53BB; VNode &#x7684; props &#x4E2D;&#x627E; <code>onXXXXX</code> &#x7684;&#x5C6C;&#x6027;&#x4F86;&#x547C;&#x53EB;&#x3002;</p>
<p>&#x65BC;&#x662F;&#xFF0C;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x5927;&#x81BD;&#x7684;&#x628A;&#x6709;&#x53D6;&#x5F97; listener &#x9700;&#x6C42;&#x7684;&#x4E8B;&#x4EF6;&#x8A3B;&#x518A;&#x6210; <code>props</code> &#x4E86;&#xFF1A;</p>
<pre><code class="language-html">&lt;template&gt;
  &lt;label&gt;
    &lt;!-- &#x9019;&#x88E1;&#x7684; $attrs &#x88E1;&#x9762;&#x5DF2;&#x7D93;&#x4E0D;&#x6703;&#x6709; onClick &#x4E86; --&gt;
    &lt;input type=&quot;text&quot; v-bind=&quot;$attrs&quot; /&gt;
  &lt;/label&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  inheritAttrs: false,
  props: [&apos;onClick&apos;], // &#x6CE8;&#x610F;&#xFF0C;&#x9019;&#x88E1;&#x8981;&#x4F7F;&#x7528; onCamelCase &#x7684;&#x5F62;&#x5F0F;
  setup(props) {
    console.log(props.onClick) // =&gt; () =&gt; {}
  },
}
&lt;/script&gt;
</code></pre>
<p>:tada: &#x5927;&#x529F;&#x544A;&#x6210;&#xFF01;</p>
<h2 id>&#x7D50;&#x8A9E;</h2>
<p>&#x96D6;&#x7136;&#x4E0D;&#x77E5;&#x9053;&#x62FF;&#x5230; listeners &#x53EF;&#x4EE5;&#x62FF;&#x4F86;&#x505A;&#x4EC0;&#x9EBC;&#xFF08;&#x9700;&#x8981;&#x547C;&#x53EB;&#x7684;&#x8A71;&#x7528; <code>$emit()</code> &#x5C31;&#x597D;&#x4E86;&#x2026;&#x2026;&#xFF09;&#xFF0C;&#x4F46;&#x81F3;&#x5C11;&#x5728; trace code &#x7684;&#x6642;&#x5019;&#x9806;&#x4FBF;&#x770B;&#x4E00;&#x4E0B; Vue.js 3 &#x662F;&#x600E;&#x9EBC;&#x8A2D;&#x8A08;&#x7684;&#x4E5F;&#x4E0D;&#x932F;XD</p>
<p>&#xFF08;BTW&#xFF0C;&#x6211;&#x662F;&#x62FF;&#x4F86;&#x5224;&#x65B7; cursor &#x8981;&#x4E0D;&#x8981;&#x662F; pointer &#x5566;&#xFF08;&#x9003;&#xFF09;</p>
<p>&#x5099;&#x8A3B;&#xFF1A; &#x539F;&#x672C;&#x7684;&#x7A0B;&#x5F0F;&#x78BC;&#x90FD;&#x662F; TypeScript&#xFF0C;&#x7B46;&#x8005;&#x5C07;&#x578B;&#x5225;&#x90E8;&#x5206;&#x53CA;&#x7121;&#x95DC;&#x90E8;&#x5206;&#x90FD;&#x7C21;&#x5316;&#x6389;&#xFF0C;&#x65B9;&#x4FBF;&#x8B80;&#x8005;&#x95B1;&#x8B80;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://v3.vuejs.org/guide/migration/listeners-removed.html?ref=blog.davy.tw">$listeners removed | Vue.js</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p><code>shared.toHandlerKey</code> &#x7684;&#x5BE6;&#x4F5C;&#x4FBF;&#x662F; <code>(str) =&gt; (str ? `on${capitalize(str)}` : ``)</code> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[在 WSL2 中使用 Ubuntu 桌面環境]]></title><description><![CDATA[雖然微軟在 BUILD 2020 上已經宣佈，未來會讓 WSL2 可以執行 GUI 應用程式，但不知道什麼時候才會正式支援這個功能，對於想體驗看看效果到底如何的我呢，就打算先在 Windows 端啓動一個 X Window Server 來嚐鮮看看]]></description><link>https://blog.davy.tw/posts/running-ubuntu-desktop-in-wsl2/</link><guid isPermaLink="false">5efc38508b52a70001c22254</guid><category><![CDATA[Windows]]></category><category><![CDATA[Linux]]></category><category><![CDATA[WSL]]></category><category><![CDATA[Ubuntu]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Wed, 08 Jul 2020 07:10:56 GMT</pubDate><media:content url="https://blog.davy.tw/content/images/2020/07/---2020-06-27-004402.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://blog.davy.tw/content/images/2020/07/---2020-06-27-004402.png" alt="&#x5728; WSL2 &#x4E2D;&#x4F7F;&#x7528; Ubuntu &#x684C;&#x9762;&#x74B0;&#x5883;"><p>&#x96D6;&#x7136;&#x5FAE;&#x8EDF;&#x5728; BUILD 2020 &#x4E0A;&#x5DF2;&#x7D93;&#x5BA3;&#x4F48;&#xFF0C;&#x672A;&#x4F86;&#x6703;&#x8B93; WSL2 &#x53EF;&#x4EE5;&#x57F7;&#x884C; GUI &#x61C9;&#x7528;&#x7A0B;&#x5F0F;<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>&#xFF0C;&#x4F46;&#x4E0D;&#x77E5;&#x9053;&#x4EC0;&#x9EBC;&#x6642;&#x5019;&#x624D;&#x6703;&#x6B63;&#x5F0F;&#x652F;&#x63F4;&#x9019;&#x500B;&#x529F;&#x80FD;&#xFF0C;&#x5C0D;&#x65BC;&#x60F3;&#x9AD4;&#x9A57;&#x770B;&#x770B;&#x6548;&#x679C;&#x5230;&#x5E95;&#x5982;&#x4F55;&#x7684;&#x6211;&#x5462;&#xFF0C;&#x5C31;&#x6253;&#x7B97;&#x5148;&#x5728; Windows &#x7AEF;&#x5553;&#x52D5;&#x4E00;&#x500B; X Window Server &#x4F86;&#x5690;&#x9BAE;&#x770B;&#x770B;&#x3002;</p>
<h2 id>&#x4E8B;&#x524D;&#x6E96;&#x5099;</h2>
<p>&#x9996;&#x5148;&#xFF0C;&#x5C0D;&#x65BC;&#x4E00;&#x500B;&#x7FD2;&#x6163; Ubuntu &#x7684;&#x6211;&#x4F86;&#x8AAA;&#xFF0C;&#x5982;&#x679C;&#x53EF;&#x4EE5;&#x9AD4;&#x9A57;&#x5230;&#x5B8C;&#x6574;&#x7684; Ubuntu &#x684C;&#x9762;&#x662F;&#x518D;&#x597D;&#x4E0D;&#x904E;&#x4E86;&#xFF0C;&#x63DB;&#x53E5;&#x8A71;&#x8AAA;&#xFF0C;&#x6211;&#x5011;&#x9700;&#x8981;&#x5728;&#x4E0A;&#x9762;&#x53EF;&#x4EE5;&#x8DD1;&#x4E00;&#x500B;&#x5B8C;&#x6574;&#x7684; Gnome Shell &#x74B0;&#x5883;&#xFF0C;&#x4E26;&#x52A0;&#x4E0A; Ubuntu &#x7684; Extension &#x5011;&#x3002;</p>
<h3 id="systemd">&#x53D6;&#x5F97;&#x5B8C;&#x6574; systemd &#x74B0;&#x5883;</h3>
<p>Gnome Shell &#x5F9E; 3.34 &#x7248;&#x958B;&#x59CB;&#xFF0C;&#x5C31;&#x5DF2;&#x7D93;&#x8DDF; systemd &#x6574;&#x5408;<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>&#x4E86;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8AAA;&#xFF0C;&#x6211;&#x5011;&#x5FC5;&#x9808;&#x8981;&#x5148;&#x6709;&#x4E00;&#x500B;&#x5B8C;&#x6574;&#x7684; systemd &#x74B0;&#x5883;&#x624D;&#x80FD;&#x9806;&#x5229;&#x7684;&#x57F7;&#x884C; Gnome Shell&#x3002;&#x7531;&#x65BC; WSL2 &#x7684;&#x5BE6;&#x4F5C;&#x6A5F;&#x5236;&#x5176;&#x5BE6;&#x662F;&#x5553;&#x52D5;&#x4E00;&#x500B; Tiny Linux VM&#xFF0C;&#x7136;&#x5F8C;&#x5229;&#x7528; Linux Namespace &#x6A5F;&#x5236;&#x4F86;&#x57F7;&#x884C;&#x4E26;&#x9694;&#x96E2;&#x5404;&#x500B;&#x767C;&#x884C;&#x7248;&#xFF0C;&#x4E26;&#x4E14;&#x7531;&#x5FAE;&#x8EDF;&#x5BE6;&#x4F5C;&#x4E86;&#x4E00;&#x500B; init (PID 1) &#x4F86;&#x8FA6;&#x5230;&#x5FEB;&#x901F;&#x5553;&#x52D5;&#x4EE5;&#x53CA;&#x4F5C;&#x70BA;&#x8207; windows &#x6E9D;&#x901A;&#x7684;&#x6A4B;&#x6A11;<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>&#x3002;</p>
<p>&#x4E5F;&#x56E0;&#x6B64;&#xFF0C;&#x5728; WSL2 &#x7684;&#x7CFB;&#x7D71;&#x88E1;&#x9762;&#xFF0C;&#x5176;&#x5BE6;&#x662F;&#x6C92;&#x6709;&#x5553;&#x7528; systemd &#x7684;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x7C21;&#x55AE;&#x7684;&#x900F;&#x904E;&#x4E0B;&#x9762;&#x7684;&#x65B9;&#x5F0F;&#x4F86;&#x6AA2;&#x67E5;&#x770B;&#x770B;&#xFF1A;</p>
<pre><code class="language-bash">$ systemctl
System has not been booted with systemd as init system (PID 1). Can&apos;t operate.
Failed to connect to bus: Host is down
$ ps u -q 1
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0    908   592 ?        Sl   10:31   0:00 /init
</code></pre>
<p>&#x53EF;&#x4EE5;&#x5F88;&#x660E;&#x986F;&#x7684;&#x770B;&#x5230;&#xFF0C;&#x7576;&#x6211;&#x5011;&#x57F7;&#x884C; <code>systemctl</code> &#x7684;&#x6642;&#x5019;&#xFF0C;&#x6703;&#x986F;&#x793A;&#x51FA;&#x6211;&#x5011;&#x7684; init system (PID 1) &#x4E26;&#x975E; systemd&#xFF0C;&#x800C;&#x662F;&#x5FAE;&#x8EDF;&#x63D0;&#x4F9B;&#x7684; <code>/init</code>&#x3002;</p>
<p>&#x90A3;&#x6211;&#x5011;&#x5982;&#x679C;&#x60F3;&#x8981;&#x64C1;&#x6709;&#x4E00;&#x500B; systemd &#x74B0;&#x5883;&#x7684;&#x8A71;&#xFF0C;&#x8A72;&#x600E;&#x9EBC;&#x8FA6;&#x5462;&#xFF1F;</p>
<p>&#x7531;&#x65BC; systemd &#x5FC5;&#x9808;&#x4EE5; PID 1 &#x7684;&#x65B9;&#x5F0F;&#x57F7;&#x884C;&#xFF0C;&#x6240;&#x4EE5;&#x76F4;&#x63A5;&#x57F7;&#x884C; systemd &#x662F;&#x6C92;&#x6709;&#x7528;&#x7684;&#xFF0C;&#x4F46;&#x591A;&#x8667;&#x4E86; Linux Namespace &#x6211;&#x5011;&#x53EF;&#x4EE5;&#x5728; WSL2 &#x4E2D;&#x5EFA;&#x7ACB;&#x65B0;&#x7684; Namespace &#x4E26;&#x628A; systemd &#x4F5C;&#x70BA; PID 1 &#x4F86;&#x57F7;&#x884C;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x5728; WSL2 &#x4E2D;&#x518D;&#x591A;&#x52A0;&#x4E00;&#x5C64; PID Namespace&#xFF0C;&#x4F7F;&#x5F97;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x5EFA;&#x7BC9;&#x4E00;&#x500B; systemd &#x7684;&#x74B0;&#x5883;&#x4E26;&#x8DF3;&#x9032;&#x9019;&#x500B;&#x65B0;&#x7684; Namespace &#x4E2D;&#x3002;</p>
<p>&#x6240;&#x5E78;&#xFF0C;&#x6211;&#x5011;&#x4E0D;&#x9700;&#x8981;&#x81EA;&#x5DF1;&#x4F86;&#x7814;&#x7A76;&#x9019;&#x90E8;&#x5206;&#x8A72;&#x5982;&#x4F55;&#x64CD;&#x4F5C;&#xFF0C;GitHub &#x4E0A;&#x5DF2;&#x7D93;&#x6709;&#x5E7E;&#x500B;&#x5C08;&#x6848;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x62FF;&#x4F86;&#x53C3;&#x8003;&#x4E26;&#x4F7F;&#x7528;&#xFF1A;</p>
<ul>
<li><a href="https://github.com/arkane-systems/genie?ref=blog.davy.tw">arkane-systems</a></li>
<li><a href="https://github.com/DamionGans/ubuntu-wsl2-systemd-script?ref=blog.davy.tw">DamionGans/ubuntu-wsl2-systemd-script</a></li>
</ul>
<p>&#x6211;&#x5011;&#x4E0B;&#x9762;&#x6703;&#x4F7F;&#x7528; <a href="https://github.com/DamionGans/ubuntu-wsl2-systemd-script?ref=blog.davy.tw">DamionGans/ubuntu-wsl2-systemd-script</a> &#x4F86;&#x7576;&#x4F5C;&#x7BC4;&#x4F8B;&#xFF0C;&#x53EA;&#x8981;&#x6309;&#x7167;&#x8AAA;&#x660E;&#x64CD;&#x4F5C;&#x5C31;&#x53EF;&#x4EE5;&#x4E86;&#xFF1A;</p>
<pre><code class="language-bash">$ git clone https://github.com/DamionGans/ubuntu-wsl2-systemd-script.git
Cloning into &apos;ubuntu-wsl2-systemd-script&apos;...
remote: Enumerating objects: 76, done.
remote: Counting objects: 100% (76/76), done.
remote: Compressing objects: 100% (55/55), done.
remote: Total 76 (delta 40), reused 41 (delta 21), pack-reused 0
Unpacking objects: 100% (76/76), 19.46 KiB | 996.00 KiB/s, done.
$ cd ubuntu-wsl2-systemd-script/
ubuntu-wsl2-systemd-script $ bash ubuntu-wsl2-systemd-script.sh
[sudo] password for davy:
Hit:1 http://security.ubuntu.com/ubuntu focal-security InRelease
Hit:2 http://archive.ubuntu.com/ubuntu focal InRelease
Hit:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease
Hit:4 http://archive.ubuntu.com/ubuntu focal-backports InRelease
Reading package lists... Done
(Reading database ... 31836 files and directories currently installed.)
Preparing to unpack .../0-dbus-user-session_1.12.16-2ubuntu2.1_amd64.deb ...
Unpacking dbus-user-session (1.12.16-2ubuntu2.1) over (1.12.16-2ubuntu2) ...
Preparing to unpack .../1-dbus-x11_1.12.16-2ubuntu2.1_amd64.deb ...
Unpacking dbus-x11 (1.12.16-2ubuntu2.1) over (1.12.16-2ubuntu2) ...
Preparing to unpack .../2-dbus_1.12.16-2ubuntu2.1_amd64.deb ...
Unpacking dbus (1.12.16-2ubuntu2.1) over (1.12.16-2ubuntu2) ...
Preparing to unpack .../3-libdbus-1-3_1.12.16-2ubuntu2.1_amd64.deb ...
Unpacking libdbus-1-3:amd64 (1.12.16-2ubuntu2.1) over (1.12.16-2ubuntu2) ...
Selecting previously unselected package daemonize.
Preparing to unpack .../4-daemonize_1.7.8-1_amd64.deb ...
Unpacking daemonize (1.7.8-1) ...
Selecting previously unselected package fontconfig.
Preparing to unpack .../5-fontconfig_2.13.1-2ubuntu3_amd64.deb ...
Unpacking fontconfig (2.13.1-2ubuntu3) ...
Setting up fontconfig (2.13.1-2ubuntu3) ...
Regenerating fonts cache... done.
Setting up libdbus-1-3:amd64 (1.12.16-2ubuntu2.1) ...
Setting up dbus (1.12.16-2ubuntu2.1) ...
Setting up daemonize (1.7.8-1) ...
Setting up dbus-x11 (1.12.16-2ubuntu2.1) ...
Setting up dbus-user-session (1.12.16-2ubuntu2.1) ...
Processing triggers for systemd (245.4-4ubuntu3) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9) ...
rm: cannot remove &apos;/lib/systemd/system/sysinit.target.wants/proc-sys-fs-binfmt_misc.mount&apos;: No such file or directory
&apos;\\wsl$\Ubuntu-20.04\home\davy\ubuntu-wsl2-systemd-script&apos;
&#x662F;&#x76EE;&#x524D;&#x7528;&#x4F86;&#x555F;&#x52D5; CMD.EXE &#x7684;&#x76EE;&#x9304;&#x8DEF;&#x5F91;&#x3002;&#x4E0D;&#x652F;&#x63F4; UNC &#x8DEF;&#x5F91;&#x3002;
&#x9810;&#x8A2D;&#x76EE;&#x9304;&#x662F; Windows &#x76EE;&#x9304;&#x3002;

&#x6210;&#x529F;: &#x5DF2;&#x7D93;&#x5132;&#x5B58;&#x6307;&#x5B9A;&#x7684;&#x503C;&#x3002;
&apos;\\wsl$\Ubuntu-20.04\home\davy\ubuntu-wsl2-systemd-script&apos;
&#x662F;&#x76EE;&#x524D;&#x7528;&#x4F86;&#x555F;&#x52D5; CMD.EXE &#x7684;&#x76EE;&#x9304;&#x8DEF;&#x5F91;&#x3002;&#x4E0D;&#x652F;&#x63F4; UNC &#x8DEF;&#x5F91;&#x3002;
&#x9810;&#x8A2D;&#x76EE;&#x9304;&#x662F; Windows &#x76EE;&#x9304;&#x3002;

&#x6210;&#x529F;: &#x5DF2;&#x7D93;&#x5132;&#x5B58;&#x6307;&#x5B9A;&#x7684;&#x503C;&#x3002;
ubuntu-wsl2-systemd-script $
</code></pre>
<p>&#x5B89;&#x88DD;&#x5B8C;&#x7562;&#x5F8C;&#x6211;&#x5011;&#x9700;&#x8981;&#x91CD;&#x5553;&#x6574;&#x500B; WSL2&#xFF0C;&#x5047;&#x5B9A;&#x6211;&#x5011;&#x7684; WSL &#x540D;&#x7A31;&#x662F; <code>ubuntu-20.04</code>&#xFF0C;&#x5728;&#x547D;&#x4EE4;&#x63D0;&#x793A;&#x5B57;&#x5143;&#xFF08;CMD&#xFF09;&#x4E2D;&#x57F7;&#x884C;&#x4E0B;&#x5217;&#x6307;&#x4EE4;&#x4EE5;&#x95DC;&#x9589; WSL2&#xFF1A;</p>
<pre><code class="language-cmd">&gt; wsl.exe -t ubuntu-20.04
</code></pre>
<p>&#x63A5;&#x8005;&#x4F7F;&#x7528;&#x4E00;&#x822C;&#x4F7F;&#x7528;&#x8005;&#x5553;&#x52D5; WSL2&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x767C;&#x73FE;&#x6709;&#x4E0D;&#x4E00;&#x6A23;&#x7684;&#x5730;&#x65B9;&#x4E86;&#xFF08;&#x591A;&#x4E86;&#x4E00;&#x500B;&#x5553;&#x52D5; systemd &#x7684;&#x63D0;&#x793A;&#xFF09;&#xFF0C;&#x900F;&#x904E;&#x6AA2;&#x67E5; PID 1 &#x4E5F;&#x53EF;&#x4EE5;&#x767C;&#x73FE;&#x6574;&#x500B;&#x74B0;&#x5883;&#x5DF2;&#x7D93;&#x662F;&#x7531; systemd &#x638C;&#x63E1;&#x4E86;&#xFF1A;</p>
<pre><code class="language-bash">Sleeping for 1 second to let systemd settle
Welcome to Ubuntu 20.04 LTS (GNU/Linux 4.19.104-microsoft-standard x86_64)

$ ps u -q 1
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  2.8  0.0 175224 12920 ?        Ss   21:48   0:06 /lib/systemd/systemd --system-unit=basic.target
$
</code></pre>
<h3 id="snap">&#x79FB;&#x9664;&#x7528;&#x4E0D;&#x5230;&#x7684; snap&#xFF08;&#x53EF;&#x9078;&#xFF09;</h3>
<p>&#x7531;&#x65BC; Ubuntu &#x5B89;&#x88DD; systemd &#x6642;&#xFF0C;&#x6703;&#x9023; snap &#x4E5F;&#x4E00;&#x4F75;&#x5553;&#x7528;&#xFF0C;&#x5982;&#x679C;&#x5927;&#x5BB6;&#x7528;&#x4E0D;&#x5230;&#x7684;&#x8A71;&#x53EF;&#x4EE5;&#x628A; snap &#x5F9E;&#x7CFB;&#x7D71;&#x4E2D;&#x79FB;&#x9664;&#xFF0C;&#x9019;&#x9EBC;&#x4E00;&#x4F86;&#x4E5F;&#x53EF;&#x4EE5;&#x63D0;&#x5347;&#x5553;&#x52D5;&#x901F;&#x5EA6;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x7CFB;&#x7D71;&#x5553;&#x52D5;&#x6642;&#x4E5F;&#x9023;&#x8457;&#x4E00;&#x4E9B; snap &#x7684;&#x5143;&#x4EF6;&#x4E00;&#x8D77;&#x5553;&#x52D5;&#x4E86;&#xFF08;&#x800C;&#x4E14;&#x9084;&#x4E0D;&#x5C11; Processes&#xFF09;&#xFF1A;</p>
<pre><code class="language-bash">$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  1.3  0.0 108788 11360 ?        Ss   22:03   0:00 /lib/systemd/systemd --system-unit=basic.targ
root          43  2.1  0.1  45248 14600 ?        S&lt;s  22:03   0:00 /lib/systemd/systemd-journald
root          61  0.4  0.0  21592  8496 ?        Ss   22:03   0:00 /lib/systemd/systemd-udevd
systemd+      63  1.2  0.0  18548  7896 ?        Ss   22:03   0:00 /lib/systemd/systemd-networkd
root         152  0.0  0.0  10572  4588 pts/0    S    22:03   0:00 /bin/login -p -f      &apos;HOSTTYPE=x86_64&apos; &apos;PWD=
root         219  1.2  0.0   3608  1792 ?        Ss   22:03   0:00 snapfuse /var/lib/snapd/snaps/core18_1705.sna
root         220  0.3  0.0   3660  1476 ?        Ss   22:03   0:00 snapfuse /var/lib/snapd/snaps/lxd_14804.snap
root         221  0.1  0.0   3488  1536 ?        Ss   22:03   0:00 snapfuse /var/lib/snapd/snaps/snapd_7264.snap
systemd+     228  1.1  0.0  24116 12592 ?        Ss   22:03   0:00 /lib/systemd/systemd-resolved
root         231  0.1  0.0 241020  9280 ?        Ssl  22:03   0:00 /usr/lib/accountsservice/accounts-daemon
message+     232  0.2  0.0   7428  4640 ?        Ss   22:03   0:00 /usr/bin/dbus-daemon --system --address=syste
root         235  0.3  0.1  29216 17788 ?        Ss   22:03   0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher
syslog       236  0.1  0.0 224328  4296 ?        Ssl  22:03   0:00 /usr/sbin/rsyslogd -n -iNONE
root         238  2.1  0.2 1457156 35432 ?       Ssl  22:03   0:00 /usr/lib/snapd/snapd
root         240  1.1  0.0  16852  7728 ?        Ss   22:03   0:00 /lib/systemd/systemd-logind
root         261  0.0  0.0 236408  9084 ?        Ssl  22:03   0:00 /usr/lib/policykit-1/polkitd --no-debug
root         302  0.0  0.0   8540  2764 ?        Ss   22:03   0:00 /usr/sbin/cron -f
root         307  0.4  0.1 108036 20512 ?        Ssl  22:03   0:00 /usr/bin/python3 /usr/share/unattended-upgrad
daemon       308  0.0  0.0   3796  2200 ?        Ss   22:03   0:00 /usr/sbin/atd -f
root         318  0.0  0.0   7356  2172 tty1     Ss+  22:03   0:00 /sbin/agetty -o -p -- \u --noclear --keep-bau
root         326  0.0  0.0   5832  1744 ?        Ss   22:03   0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
davy         376  0.2  0.0  18444  9612 ?        Ss   22:03   0:00 /lib/systemd/systemd --user
davy         377  0.0  0.0 110132  3188 ?        S    22:03   0:00 (sd-pam)
davy         387  0.2  0.0  10048  4992 pts/0    S    22:03   0:00 -bash
davy         431  0.0  0.0  10604  3224 pts/0    R+   22:04   0:00 ps aux
$
</code></pre>
<p>&#x9996;&#x5148;&#x6211;&#x5011;&#x5148;&#x5C07;&#x6240;&#x6709; snap &#x90FD;&#x5217;&#x51FA;&#x5F8C;&#xFF0C;&#x4E00;&#x500B;&#x4E00;&#x500B;&#x79FB;&#x9664;&#xFF1A;</p>
<pre><code class="language-bash">$ snap list
Name    Version   Rev    Tracking         Publisher   Notes
core18  20200311  1705   latest/stable    canonical&#x2713;  base
lxd     4.0.1     14804  latest/stable/&#x2026;  canonical&#x2713;  -
snapd   2.44.3    7264   latest/stable    canonical&#x2713;  snapd
# snap remove lxd
# snap remove core18
# snap remove snapd
$ snap list
No snaps are installed yet. Try &apos;snap install hello-world&apos;.
# apt purge snapd
$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.6  0.0 109692 12692 ?        Ss   22:03   0:03 /lib/systemd/systemd --system-unit=basic.targ
root          43  0.1  0.1  53444 15456 ?        S&lt;s  22:03   0:00 /lib/systemd/systemd-journald
root          61  0.0  0.0  21592  8496 ?        Ss   22:03   0:00 /lib/systemd/systemd-udevd
systemd+      63  0.1  0.0  18548  7896 ?        Ss   22:03   0:00 /lib/systemd/systemd-networkd
root         152  0.0  0.0  10572  4588 pts/0    S    22:03   0:00 /bin/login -p -f      &apos;HOSTTYPE=x86_64&apos; &apos;PWD=
systemd+     228  0.0  0.0  24116 12592 ?        Ss   22:03   0:00 /lib/systemd/systemd-resolved
root         231  0.0  0.0 241020  9280 ?        Ssl  22:03   0:00 /usr/lib/accountsservice/accounts-daemon
message+     232  0.0  0.0   7428  4640 ?        Ss   22:03   0:00 /usr/bin/dbus-daemon --system --address=syste
root         235  0.0  0.1  29216 17788 ?        Ss   22:03   0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher
syslog       236  0.0  0.0 224328  4296 ?        Ssl  22:03   0:00 /usr/sbin/rsyslogd -n -iNONE
root         240  0.1  0.0  16852  7728 ?        Ss   22:03   0:00 /lib/systemd/systemd-logind
root         261  0.0  0.0 236408  9084 ?        Ssl  22:03   0:00 /usr/lib/policykit-1/polkitd --no-debug
root         302  0.0  0.0   8540  2764 ?        Ss   22:03   0:00 /usr/sbin/cron -f
root         307  0.0  0.1 108036 20512 ?        Ssl  22:03   0:00 /usr/bin/python3 /usr/share/unattended-upgrad
daemon       308  0.0  0.0   3796  2200 ?        Ss   22:03   0:00 /usr/sbin/atd -f
root         318  0.0  0.0   7356  2172 tty1     Ss+  22:03   0:00 /sbin/agetty -o -p -- \u --noclear --keep-bau
root         326  0.0  0.0   5832  1744 ?        Ss   22:03   0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
davy         376  0.0  0.0  18444  9708 ?        Ss   22:03   0:00 /lib/systemd/systemd --user
davy         377  0.0  0.0 110132  3188 ?        S    22:03   0:00 (sd-pam)
davy         387  0.0  0.0  10180  5252 pts/0    S    22:03   0:00 -bash
root        1168  0.0  0.1 283780 15888 ?        Ssl  22:07   0:00 /usr/lib/packagekit/packagekitd
davy        1273  0.0  0.0  10604  3316 pts/0    R+   22:11   0:00 ps aux
</code></pre>
<p>&#x7D50;&#x675F;&#x5F8C;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x767C;&#x73FE; Processes &#x6578;&#x91CF;&#x6E1B;&#x5C11;&#x4E86;&#x8A31;&#x591A;&#xFF0C;&#x8B93;&#x6211;&#x5011;&#x7684;&#x74B0;&#x5883;&#x53C8;&#x7A0D;&#x5FAE;&#x8F15;&#x91CF;&#x4E86;&#x4E9B;&#x3002;</p>
<h3 id="windowsxwindowserver">&#x5728; Windows &#x6E96;&#x5099; X Window Server</h3>
<p>&#x9019;&#x908A;&#x6709;&#x5F88;&#x591A;&#x9078;&#x64C7;&#xFF0C;&#x6211;&#x9078;&#x64C7;&#x4E86; X410<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>&#xFF08;&#x4ED8;&#x8CBB;&#xFF09;&#xFF0C;&#x5927;&#x5BB6;&#x4E5F;&#x53EF;&#x4EE5;&#x9078;&#x64C7; VcXsrv<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup> &#x4E4B;&#x985E;&#x7684;&#x89E3;&#x6C7A;&#x65B9;&#x6848;&#xFF0C;&#x9019;&#x908A;&#x5C31;&#x4E0D;&#x591A;&#x8D05;&#x8FF0;&#x4E86;&#xFF0C;&#x5728;&#x9019;&#x88E1;&#x7684;&#x7BC4;&#x4F8B;&#x4E2D;&#x6703;&#x9700;&#x8981;&#x5C07; X Window Server &#x958B;&#x5728; Windows &#x7684; 6000 port &#x4E0A;&#x3002;</p>
<h2 id="ubuntu">&#x5B89;&#x88DD; Ubuntu &#x684C;&#x9762;</h2>
<p>&#x63A5;&#x8457;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x4F86;&#x5B89;&#x88DD; Ubuntu &#x7684;&#x9810;&#x8A2D;&#x684C;&#x9762;&#x4E86;&#xFF0C;&#x9019;&#x88E1;&#x6703;&#x9700;&#x8981;&#x6BD4;&#x8F03;&#x591A;&#x7684;&#x786C;&#x789F;&#x7A7A;&#x9593;&#xFF1A;</p>
<pre><code class="language-bash"># apt install ubuntu-desktop
...
10 upgraded, 1077 newly installed, 0 to remove and 64 not upgraded.
Need to get 605 MB of archives.
After this operation, 2260 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
...
</code></pre>
<p>&#x5B89;&#x88DD;&#x7D50;&#x675F;&#x5F8C;&#xFF0C;&#x6211;&#x5011;&#x9700;&#x8981;&#x5148;&#x53D6;&#x5F97; Windows &#x7684; IP &#x4F4D;&#x7F6E;<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>&#xFF0C;&#x4E26;&#x5617;&#x8A66;&#x5C0D; X Window Server &#x9023;&#x7DDA;&#x770B;&#x770B;&#xFF1A;</p>
<pre><code class="language-bash">$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.17.160.1
$ nc -v 172.17.160.1 6000
Connection to 172.17.160.1 6000 port [tcp/x11] succeeded!
^C
$
</code></pre>
<p>&#x6210;&#x529F;&#x9023;&#x7DDA;&#x5F8C;&#xFF0C;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x64B0;&#x5BEB;&#x4E00;&#x500B;&#x5553;&#x52D5;&#x8173;&#x672C;&#xFF0C;&#x5C07; <code>DISPLAY</code> &#x6307;&#x5411; Windows &#x4E0A;&#x7684; X Window Server &#x4E2D;&#x4E26;&#x4E14;&#x52A0;&#x4E0A;&#x4E00;&#x4E9B; Ubuntu &#x684C;&#x9762;&#x7684;&#x8A2D;&#x5B9A;&#x5F8C;&#x57F7;&#x884C; Gnome Shell&#xFF1A;</p>
<pre><code class="language-bash">$ cat - &gt; gnome.sh &lt;&lt;&apos;EOF&apos;
#!/bin/bash
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk &apos;{print $2}&apos;):0.0;
export XDG_SESSION_TYPE=&quot;x11&quot;
export XDG_RUNTIME_DIR=~/.cache/xdg
export XDG_SESSION_CLASS=&quot;user&quot;
export XDG_SESSION_DESKTOP=ubuntu
export XDG_CURRENT_DESKTOP=ubuntu:GNOME
export DESKTOP_SESSION=ubuntu
export GDMSESSION=ubuntu
export GNOME_SHELL_SESSION_MODE=ubuntu

gnome-session &quot;$@&quot;
EOF
$ chmod +x gnome.sh
$ ./gnome.sh
</code></pre>
<p><img src="https://i.imgur.com/6349tng.png" alt="&#x5728; WSL2 &#x4E2D;&#x4F7F;&#x7528; Ubuntu &#x684C;&#x9762;&#x74B0;&#x5883;" loading="lazy"></p>
<p>&#x7576;&#x7136;&#xFF0C;&#x5982;&#x679C;&#x60F3;&#x8981;&#x5728;&#x9019;&#x500B;&#x684C;&#x9762;&#x4E2D;&#x57F7;&#x884C; Windows CMD &#x4E5F;&#x662F;&#x6C92;&#x6709;&#x554F;&#x984C;&#x7684;&#xFF0C;&#x800C;&#x7CFB;&#x7D71;&#x4E5F;&#x53EF;&#x4EE5;&#x6B63;&#x78BA;&#x7684;&#x5075;&#x6E2C;&#x5230; Virtualization &#x662F; WSL &#x5462;&#x3002;</p>
<p><img src="https://i.imgur.com/n4YNLbD.png" alt="&#x5728; WSL2 &#x4E2D;&#x4F7F;&#x7528; Ubuntu &#x684C;&#x9762;&#x74B0;&#x5883;" loading="lazy"></p>
<h3 id="systemdresolved">&#x95DC;&#x9589; systemd-resolved</h3>
<p>&#x9019;&#x88E1;&#x662F;&#x4E00;&#x500B;&#x53EF;&#x9078;&#x7684;&#x9805;&#x76EE;&#xFF0C;&#x7531;&#x65BC;&#x7B46;&#x8005;&#x5728;&#x900F;&#x904E; <code>/etc/resolv.conf</code> &#x53D6;&#x5F97; Windows IP &#x6642;&#x6709;&#x9047;&#x5230; <code>resolv.conf</code> &#x88AB; systemd-resolved &#x66FF;&#x63DB;&#x6210; <code>127.0.0.53</code> &#x7684;&#x554F;&#x984C;&#xFF0C;&#x9019;&#x908A;&#x63D0;&#x4F9B;&#x4E00;&#x500B;&#x65B9;&#x5F0F;&#x5C07;&#x9019;&#x500B;&#x6771;&#x897F;&#x505C;&#x7528;&#xFF0C;&#x64CD;&#x4F5C;&#x5B8C;&#x91CD;&#x5553; WSL2 &#x5373;&#x53EF;&#xFF1A;</p>
<pre><code class="language-bash"># systemctl stop systemd-resolved
# systemctl disable systemd-resolved
Removed /etc/systemd/system/multi-user.target.wants/systemd-resolved.service.
Removed /etc/systemd/system/dbus-org.freedesktop.resolve1.service.
</code></pre>
<h2 id>&#x5F8C;&#x8A18;</h2>
<p>&#x7531;&#x65BC;&#x76EE;&#x524D;&#x7684; WSL2 &#x9084;&#x6C92;&#x6709; GPGPU &#x52A0;&#x901F;&#xFF0C;&#x6240;&#x4EE5;&#x62FF;&#x4F86;&#x57F7;&#x884C; GUI &#x7A0B;&#x5F0F;&#x7684;&#x8A71;&#x53EF;&#x80FD;&#x9084;&#x662F;&#x6703;&#x6709;&#x9EDE; lag&#xFF0C;&#x5FAE;&#x8EDF;&#x63D0;&#x51FA;&#x7684;&#x6700;&#x7D42;&#x65B9;&#x6848;&#x662F;&#x900F;&#x904E; RDP &#x4F86;&#x57F7;&#x884C; GUI &#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x4E5F;&#x8A31;&#x6703;&#x900F;&#x904E; RemoteApp &#x4F86;&#x5C07;&#x986F;&#x5361;&#x52A0;&#x901F;&#x505A;&#x5728; Windows &#x7AEF;&#xFF0C;&#x4F46;&#x4F5C;&#x70BA;&#x5690;&#x9BAE;&#x4E00;&#x4E0B;&#xFF0C;&#x76EE;&#x524D;&#x7684;&#x7D50;&#x679C;&#x5DF2;&#x7D93;&#x7B97;&#x662F;&#x9084;&#x53EF;&#x4EE5;&#x7684;&#x4E86;XD</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x5FAE;&#x8EDF;&#x5728; BUILD 2020 &#x4E0A;&#x5BA3;&#x4F48;&#xFF0C;&#x5C07;&#x6703;&#x8B93; WSL2 &#x53EF;&#x4EE5;&#x57F7;&#x884C; GUI &#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#xFF0C;&#x4E26;&#x4F7F;&#x7528; Wayland &#x914D;&#x5408; RDP Protocol &#x4F86;&#x5BE6;&#x4F5C;&#x9019;&#x500B;&#x529F;&#x80FD;&#xFF0C;&#x8A73;&#x898B;&#x5FAE;&#x8EDF;&#x90E8;&#x843D;&#x683C;&#x3008;<a href="https://devblogs.microsoft.com/commandline/the-windows-subsystem-for-linux-build-2020-summary/?ref=blog.davy.tw#wsl-gui">The Windows Subsystem for Linux BUILD 2020 Summary</a>&#x3009;&#x4E00;&#x6587; <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>&#x95DC;&#x65BC; Gnome Shell &#x7684;&#x9019;&#x500B;&#x8B8A;&#x5316;&#xFF0C;&#x53EF;&#x4EE5;&#x53C3;&#x8003; Gnome Blog &#x7684;&#x3008;<a href="https://blogs.gnome.org/benzea/2019/10/01/gnome-3-34-is-now-managed-using-systemd/?ref=blog.davy.tw">GNOME 3.34 is now managed using systemd</a>&#x3009;&#x4E00;&#x6587;&#x3002; <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>&#x5C0D;&#x65BC; WSL2 &#x7684;&#x8A73;&#x7D30;&#x67B6;&#x69CB;&#xFF0C;&#x53EF;&#x4EE5;&#x53C3;&#x8003; BUILD 2019 &#x7684;&#x3008;<a href="https://www.youtube.com/watch?v=lwhMThePdIo&amp;ref=blog.davy.tw">The new Windows subsystem for Linux architecture: a deep dive - BRK3068</a>&#x3009;&#x8B70;&#x7A0B;&#x3002; <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p><a href="https://x410.dev/?ref=blog.davy.tw">https://x410.dev/</a> <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p><a href="https://sourceforge.net/projects/vcxsrv/?ref=blog.davy.tw">https://sourceforge.net/projects/vcxsrv/</a> <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p><a href="https://docs.microsoft.com/zh-tw/windows/wsl/compare-versions?ref=blog.davy.tw#accessing-network-applications">https://docs.microsoft.com/zh-tw/windows/wsl/compare-versions#accessing-network-applications</a> <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[在 Vue 中讓 localStorage 支援回應式設計]]></title><description><![CDATA[在許多當紅的網頁前端框架中，都採用了回應式設計（Reactive Design），讓狀態變化時自動通知框架來對視圖（View）進行重繪，但通常這麼方便的功能只會支援框架自己提出的 state 模型上，而這次我們來談談如何在 Vue.js 中使用 localStorage 並支援回應式設計吧]]></description><link>https://blog.davy.tw/posts/how-to-make-localstorage-reactive-vue/</link><guid isPermaLink="false">5ef9fb488b52a70001c21feb</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Mon, 29 Jun 2020 19:24:38 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x5728;&#x8A31;&#x591A;&#x7576;&#x7D05;&#x7684;&#x7DB2;&#x9801;&#x524D;&#x7AEF;&#x6846;&#x67B6;&#x4E2D;&#xFF0C;&#x90FD;&#x63A1;&#x7528;&#x4E86;&#x56DE;&#x61C9;&#x5F0F;&#x8A2D;&#x8A08;&#xFF08;Reactive Design&#xFF09;&#xFF0C;&#x8B93;&#x72C0;&#x614B;&#x8B8A;&#x5316;&#x6642;&#x81EA;&#x52D5;&#x901A;&#x77E5;&#x6846;&#x67B6;&#x4F86;&#x5C0D;&#x8996;&#x5716;&#xFF08;View&#xFF09;&#x9032;&#x884C;&#x91CD;&#x7E6A;&#xFF0C;&#x4F46;&#x901A;&#x5E38;&#x9019;&#x9EBC;&#x65B9;&#x4FBF;&#x7684;&#x529F;&#x80FD;&#x53EA;&#x6703;&#x652F;&#x63F4;&#x6846;&#x67B6;&#x81EA;&#x5DF1;&#x63D0;&#x51FA;&#x7684; state &#x6A21;&#x578B;&#x4E0A;&#xFF0C;&#x800C;&#x9019;&#x6B21;&#x6211;&#x5011;&#x4F86;&#x8AC7;&#x8AC7;&#x5982;&#x4F55;&#x5728; Vue.js<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> &#x4E2D;&#x4F7F;&#x7528; localStorage<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x4E26;&#x652F;&#x63F4;&#x56DE;&#x61C9;&#x5F0F;&#x8A2D;&#x8A08;&#x5427;&#x3002;</p>
<h2 id="reactivity">Reactivity<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup></h2>
<p>&#x5728; Vue.js &#x4E2D;&#xFF0C;&#x5404;&#x500B;&#x5143;&#x4EF6;&#xFF08;Component&#xFF09;&#x4E2D;&#x90FD;&#x6709;&#x4E00;&#x500B; <code>$data</code> &#x6B04;&#x4F4D;&#xFF0C;&#x7528;&#x4EE5;&#x5B58;&#x653E;&#x56DE;&#x61C9;&#x5F0F;&#x7684;&#x72C0;&#x614B;&#xFF0C;Vue.js &#x6703;&#x5728;&#x72C0;&#x614B;&#x5167;&#x90E8;&#x6539;&#x8B8A;&#x6642;&#xFF0C;&#x901A;&#x77E5;&#x4E26;&#x91CD;&#x7E6A;&#x8996;&#x5716;&#x3002;&#x4F46;&#x5728;&#x4E00;&#x822C;&#x7684;&#x60C5;&#x6CC1;&#x4E0B;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x662F;&#x5B58;&#x653E;&#x5728; <code>$data</code> &#x4E0B;&#x7684;&#x72C0;&#x614B;&#x662F;&#x4E0D;&#x6703;&#x88AB;&#x8FFD;&#x8E64;&#x7684;&#xFF0C;&#x9664;&#x975E;&#x6211;&#x5011;&#x624B;&#x52D5;&#x8DDF; Vue.js &#x8A3B;&#x518A;&#x9019;&#x500B;&#x7269;&#x4EF6;&#xFF0C;&#x5982;&#x4E0B;&#x7BC4;&#x4F8B;&#x6240;&#x793A;&#xFF1A;</p>
<pre><code class="language-javascript">new Vue({
  el: &apos;#app&apos;,
  data: {
    foo: 1,
  },
  created() {
    this.bar = 2
  },
  methods: {
    addFoo() {
      this.foo += 1
    },
    addBar() {
      this.bar += 1
    },
  },
})
</code></pre>
<p class="codepen" data-height="160" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="jOWGYYE" style="height: 160px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="jOWGYYE">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/jOWGYYE?ref=blog.davy.tw">
  jOWGYYE</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<p>&#x9664;&#x975E;&#x56E0;&#x70BA;&#x6211;&#x5011;&#x6539;&#x8B8A;&#x4E86; <code>this.foo</code> &#x800C;&#x89F8;&#x767C;&#x66F4;&#x65B0;&#xFF0C;&#x5426;&#x5247;&#x6539;&#x8B8A; <code>this.bar</code> &#x503C;&#x7684;&#x6642;&#x5019;&#x4E26;&#x4E0D;&#x6703;&#x89F8;&#x767C;&#x66F4;&#x65B0;&#x3002;</p>
<p>&#x90A3;&#x662F;&#x56E0;&#x70BA;&#x5728;&#x521D;&#x59CB;&#x5316;&#x5143;&#x4EF6;&#x6642;&#xFF0C;Vue &#x6703;&#x5C0D;&#x5B9A;&#x7FA9;&#x597D;&#x7684; <code>$data</code> &#x9032;&#x884C; Hook&#xFF0C;&#x8B93;&#x88E1;&#x9762;&#x6BCF;&#x500B;&#x6B04;&#x4F4D;&#x7684;&#x8B8A;&#x5316;&#x90FD;&#x53EF;&#x4EE5;&#x88AB; Vue &#x6240;&#x5075;&#x6E2C;&#xFF0C;&#x800C; Vue &#x5176;&#x5BE6;&#x4E5F;&#x6709;&#x63D0;&#x4F9B; API &#x8B93;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x81EA;&#x5DF1;&#x4F86;&#x5BE6;&#x4F5C;&#x88AB; Vue &#x807D;&#x7684;&#x7269;&#x4EF6;&#xFF0C;&#x4E0B;&#x9762;&#x6709;&#x5169;&#x500B;&#x7BC4;&#x4F8B;&#xFF1A;</p>
<pre><code class="language-javascript">// Hook whole object
const foobar = Vue.observable({ fb: 3 })

new Vue({
  el: &apos;#app&apos;,
  data: {
    foo: 1,
  },
  created() {
    this.foobar = foobar
    // Hook only on bar field
    Vue.util.defineReactive(this, &apos;bar&apos;, 2)
  },
  methods: {
    addFoo() {
      this.foo += 1
    },
    addBar() {
      this.bar += 1
    },
    addFooBar() {
      this.foobar.fb += 1
    }
  },
})
</code></pre>
<p class="codepen" data-height="200" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="JjGrMzL" style="height: 200px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="JjGrMzL">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/JjGrMzL?ref=blog.davy.tw">
  JjGrMzL</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<p>Vue &#x7684;&#x884C;&#x70BA;&#x5176;&#x5BE6;&#x662F;&#x5229;&#x7528;&#x4E86; <code>Object.defineProperty</code><sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup> &#x4F86;&#x5EFA;&#x7ACB;&#x8207;&#x6B04;&#x4F4D;&#x540C;&#x540D;&#x7684; Getter/Setter<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup>&#xFF0C;&#x4E26;&#x5728;&#x6211;&#x5011;&#x547C;&#x53EB;&#x4F7F;&#x7528;&#x6642;&#x8A18;&#x9304;&#x4E0B;&#x9019;&#x4E4B;&#x9593;&#x7684;&#x76F8;&#x4F9D;&#x95DC;&#x4FC2;&#xFF0C;&#x5728;&#x585E;&#x5165;&#x65B0;&#x503C;&#x7684;&#x6642;&#x5019;&#x901A;&#x77E5;&#x9019;&#x4E9B;&#x88AB;&#x76F8;&#x4F9D;&#x7684;&#x90E8;&#x5206;&#x4F86;&#x9032;&#x884C;&#x66F4;&#x65B0;<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>&#xFF1A;</p>
<pre><code class="language-javascript">// vue@2.6.11:src/core/observer/index.js
export function defineReactive (obj, key, ...) {
  const dep = new Dep()
  // ...
  Object.defineProperty(obj, key, {
    // ...
    get() {
      // ...
      dep.depend()
      // ...
    },
    set(newVal) {
      // ...
      dep.notify()
    }
  })
}
</code></pre>
<p>&#x800C;&#x5728;&#x8A72;&#x7269;&#x4EF6;&#x672C;&#x4F86;&#x5C31;&#x6709; Getter/Setter &#x7684;&#x60C5;&#x6CC1;&#x4E0B;&#xFF0C;Vue &#x4E5F;&#x6703;&#x5728; Hook &#x4E2D;&#x9032;&#x884C;&#x547C;&#x53EB;&#x4EE5;&#x9054;&#x5230;&#x8207;&#x5927;&#x90E8;&#x5206;&#x7269;&#x4EF6;&#x76F8;&#x5BB9;&#x7684;&#x53EF;&#x80FD;&#x6027;&#x3002;</p>
<h2 id="localstoragevuejsplugin">&#x8A2D;&#x8A08;&#x7C21;&#x6613; localStorage Vue.js Plugin</h2>
<p>&#x77AD;&#x89E3;&#x4E86; Vue &#x4E2D; Reactivity &#x7684;&#x6A5F;&#x5236;&#x4E4B;&#x5F8C;&#xFF0C;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x4F86;&#x8A2D;&#x8A08;&#x4E00;&#x4E0B;&#x6211;&#x5011;&#x7406;&#x60F3;&#x4E2D;&#x7684;&#x529F;&#x80FD;&#x4EE5;&#x53CA;&#x8A72;&#x5982;&#x4F55;&#x9032;&#x884C;&#x5BE6;&#x4F5C;&#xFF0C;localStorage &#x6709;&#x6C38;&#x7E8C;&#x6027;&#x5132;&#x5B58;&#x53CA;&#x8DE8;&#x700F;&#x89BD;&#x9801;&#x72C0;&#x614B;&#x7684;&#x7279;&#x6027;&#xFF0C;&#x9069;&#x5408;&#x505A;&#x4E00;&#x4E9B;&#x8F03;&#x70BA;&#x9032;&#x968E;&#x7684;&#x529F;&#x80FD;&#x3002;&#x7E3D;&#x4E4B;&#xFF0C;&#x6211;&#x5011;&#x5148;&#x4F86;&#x8A2D;&#x8A08;&#x4E00;&#x500B;&#x7C21;&#x55AE;&#x7684; PoC &#x8B93; Vue &#x6703;&#x4F9D;&#x64DA; localStorage &#x7684;&#x5167;&#x5BB9;&#x4F5C;&#x51FA;&#x66F4;&#x65B0;&#xFF1A;</p>
<pre><code class="language-javascript">class LocalStorage {
  static install (Vue, options) {
    const instance = new LocalStorage(Vue, options)
    
    Object.defineProperty(Vue.prototype, &apos;$localStorage&apos;, {
      get: () =&gt; instance.storage,
    })

    Vue.localStorage = instance.storage
    
    return instance
  }
  
  static pack (value) {
    if (value === undefined)
      return undefined
    
    return JSON.stringify(value)
  }
  static unpack (value) {
    if (value === undefined)
      return undefined

    try {
      return JSON.parse(value)
    } catch (e) {
      return value
    }
  }

  constructor (Vue, { fields = [] }) {
    const storage = {}
    fields.forEach((property) =&gt; {
      Object.defineProperty(storage, property, {
        get: () =&gt; LocalStorage.unpack(window.localStorage.getItem(property)),
        set: (val) =&gt; window.localStorage.setItem(property, LocalStorage.pack(val)),
        configurable: true,
      })
      
      Vue.util.defineReactive(storage, property, storage[property])
    })
    
    this.storage = storage
  }
}

Vue.use(LocalStorage, {
  fields: [&apos;num&apos;],
})

new Vue({
  el: &apos;#app&apos;,
  created() {
    if (this.$localStorage.num === undefined)
      this.$localStorage.num = 0
  },
  methods: {
    add() {
      this.$localStorage.num += 1
    },
  },
})
</code></pre>
<p class="codepen" data-height="170" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="ZEQXrar" style="height: 170px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="ZEQXrar">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/ZEQXrar?ref=blog.davy.tw">
  ZEQXrar</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<p>&#x5F9E;&#x4E0A;&#x9762;&#x7684; PoC &#x4E2D;&#x5DF2;&#x7D93;&#x53EF;&#x4EE5;&#x767C;&#x73FE;&#xFF0C;&#x6211;&#x5011;&#x5728;&#x8DE8;&#x5143;&#x4EF6;&#x751A;&#x81F3;&#x662F;&#x8DE8; Vue &#x5BE6;&#x4F8B;&#x7684;&#x60C5;&#x6CC1;&#x4E0B;&#x5DF2;&#x7D93;&#x53EF;&#x4EE5;&#x6210;&#x529F;&#x7684;&#x540C;&#x6B65; <code>Vue.localStorage</code> &#x4E2D;&#x7684;&#x6771;&#x897F;&#x4E86;&#x3002;&#x6211;&#x5011;&#x5C31;&#x5148;&#x4EE5;&#x9019;&#x500B; PoC &#x4F86;&#x89E3;&#x91CB;&#x6574;&#x9AD4;&#x7684;&#x601D;&#x8DEF;&#x5427;&#xFF1A;</p>
<h3 id="vuejsplugininterface">Vue.js Plugin Interface<sup class="footnote-ref"><a href="#fn7" id="fnref7">[7]</a></sup></h3>
<p>Vue &#x4E2D;&#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x500B;&#x8A3B;&#x518A; Plugin &#x7684;&#x65B9;&#x6CD5;&#xFF1A;</p>
<pre><code class="language-javascript">Vue.use(Plugin)
</code></pre>
<p>&#x800C; Vue &#x6703;&#x53BB;&#x547C;&#x53EB; <code>Plugin.install</code> &#x65B9;&#x6CD5;&#xFF0C;&#x4E26;&#x5C07; Vue &#x4EE5;&#x53CA;&#x50B3;&#x5165; <code>Vue.use</code> &#x7684;&#x53C3;&#x6578;&#x90FD;&#x50B3;&#x5165;&#x9019;&#x500B;&#x65B9;&#x6CD5;&#x4E2D;&#xFF0C;&#x5982;&#x6B64;&#x4EE5;&#x4F86;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x53D6;&#x5F97;&#x6211;&#x5011;&#x8981;&#x64F4;&#x5145;&#x7684;&#x9019;&#x500B; Vue&#xFF08;&#x5982;&#x679C;&#x4F60;&#x540C;&#x6642;&#x6709;&#x5F88;&#x591A; Vue &#x5BE6;&#x4F5C;&#x7684;&#x8A71;&#x2026;&#x2026;&#xFF09;&#xFF0C;&#x6211;&#x5011;&#x5728;&#x9019;&#x88E1;&#x53EA;&#x8981;&#x505A;&#x597D; Vue &#x7684;&#x64F4;&#x5145;&#x5C31;&#x597D;&#x4E86;&#xFF0C;&#x6709;&#x95DC;&#x5B58;&#x53D6; localStorage &#x7684;&#x5BE6;&#x4F5C;&#x6211;&#x5011;&#x653E;&#x5230; <code>LocalStorage</code> &#x9019;&#x500B; class &#x4E2D;&#x9032;&#x884C;&#xFF1A;</p>
<pre><code class="language-javascript">class LocalStorage {
  // &#x5B9A;&#x7FA9; LocalStorage.install
  static install (Vue, options) {
    const instance = new LocalStorage(Vue, options)
    
    // &#x5B9A;&#x7FA9; vm.$localStorage
    Object.defineProperty(Vue.prototype, &apos;$localStorage&apos;, {
      get: () =&gt; instance.storage,
    })

    // &#x5B9A;&#x7FA9; Vue.localStorage
    Vue.localStorage = instance.storage
    
    return instance
  }
}
</code></pre>
<h3 id="localstorage">&#x5BE6;&#x969B;&#x64CD;&#x4F5C; localStorage</h3>
<p>&#x5728;&#x5BE6;&#x969B;&#x5BE6;&#x4F5C; localStorage &#x7684;&#x6642;&#x5019;&#xFF0C;&#x6211;&#x5011;&#x6253;&#x7B97;&#x8B93;&#x7269;&#x4EF6;&#x7684;&#x578B;&#x5225;&#x5118;&#x53EF;&#x80FD;&#x7684;&#x4FDD;&#x7559;&#x4E0B;&#x4F86;&#xFF0C;&#x9019;&#x908A;&#x4F7F;&#x7528;&#x6700;&#x7C21;&#x55AE;&#x7684;&#x65B9;&#x5F0F;&#x5BE6;&#x4F5C; &#x2014;&#x2014; &#x900F;&#x904E; <code>JSON.stringify</code><sup class="footnote-ref"><a href="#fn8" id="fnref8">[8]</a></sup>/<code>JSON.parse</code><sup class="footnote-ref"><a href="#fn9" id="fnref9">[9]</a></sup>&#xFF0C;&#x5118;&#x7BA1;&#x9019;&#x88E1;&#x6703;&#x628A;&#x4E00;&#x4E9B;&#x81EA;&#x5B9A;&#x7269;&#x4EF6;&#x7D66;&#x7D71;&#x7D71;&#x8F49;&#x63DB;&#x70BA; JSON &#x5132;&#x5B58;&#x800C;&#x4E1F;&#x5931;&#x578B;&#x5225;&#xFF0C;&#x4F46;&#x5148;&#x6C42;&#x6709;&#x518D;&#x6C42;&#x597D;&#xFF0C;&#x4E4B;&#x5F8C;&#x53EF;&#x4EE5;&#x518D;&#x4F86;&#x6C7A;&#x5B9A;&#x5E8F;&#x5217;&#x5316;/&#x53CD;&#x5E8F;&#x5217;&#x5316;&#x7684;&#x65B9;&#x6CD5;&#xFF1A;</p>
<pre><code class="language-javascript">class LocalStorage {
  // &#x5E8F;&#x5217;&#x5316;
  static pack (value) {
    if (value === undefined)
      return undefined
    
    return JSON.stringify(value)
  }
  // &#x53CD;&#x5E8F;&#x5217;&#x5316;
  static unpack (value) {
    if (value === undefined)
      return undefined

    try {
      return JSON.parse(value)
    } catch (e) {
      return value
    }
  }

  constructor (Vue, { fields = [] }) {
    const storage = {}
    // &#x5C0D;&#x6BCF;&#x500B;&#x6307;&#x5B9A;&#x7684; fields &#x9032;&#x884C;&#x5B9A;&#x7FA9;
    fields.forEach((property) =&gt; {
      // &#x5B9A;&#x7FA9;&#x5C0D;&#x61C9;&#x7684; Getter/Setter &#x4EE5;&#x76F4;&#x63A5;&#x5B58;&#x53D6; localStorage
      Object.defineProperty(storage, property, {
        get: () =&gt; LocalStorage.unpack(window.localStorage.getItem(property)),
        set: (val) =&gt; window.localStorage.setItem(property, LocalStorage.pack(val)),
        // &#x8A2D;&#x70BA; configurable &#x4EE5;&#x8B93; Vue &#x9032;&#x884C; Hook
        configurable: true,
      })
      // &#x8B93; Vue hook &#x5C0D;&#x61C9;&#x6B04;&#x4F4D;
      Vue.util.defineReactive(storage, property, storage[property])
    })
    
    this.storage = storage
  }
}
</code></pre>
<p>&#x6211;&#x5011;&#x9019;&#x908A;&#x4F7F;&#x7528;&#x4E00;&#x500B;&#x7A7A;&#x7684; <code>storage</code> &#x7269;&#x4EF6;&#x4F86;&#x9032;&#x884C; <code>Object.defineProperty</code> &#x8B93;&#x6211;&#x5011;&#x6307;&#x5B9A;&#x7684;&#x6B04;&#x4F4D;&#x5011;&#x5728;&#x9019;&#x500B;&#x7269;&#x4EF6;&#x4E0A;&#x90FD;&#x6709;&#x53D7; Vue &#x76E3;&#x807D;&#x7684; Getter/Setter&#xFF0C;&#x5982;&#x6B64;&#x4EE5;&#x4F86;&#x5C31;&#x53EF;&#x4EE5;&#x7C21;&#x55AE;&#x7684;&#x5728;&#x540C;&#x4E00;&#x500B;&#x9801;&#x9762;&#x4E0A;&#x5206;&#x4EAB; localStorage &#x4E86;&#x3002;</p>
<h2 id="localstorageplugin">&#x6539;&#x826F; LocalStorage Plugin</h2>
<h3 id>&#x8DE8;&#x9801;&#x9762;&#x540C;&#x6B65;&#x66F4;&#x65B0;</h3>
<p>&#x54A6;&#xFF1F;&#x6211;&#x525B;&#x525B;&#x662F;&#x8AAA;&#x4E86;&#x300C;&#x53EF;&#x4EE5;&#x7C21;&#x55AE;&#x7684;&#x5728;&#x540C;&#x4E00;&#x500B;&#x9801;&#x9762;&#x4E0A;&#x5206;&#x4EAB; localStorage&#x300D;&#x55CE;&#xFF1F;</p>
<p>&#x5982;&#x679C;&#x5404;&#x4F4D;&#x628A;&#x4E0A;&#x9762;&#x7684;&#x7BC4;&#x4F8B;&#x958B;&#x5230;&#x4E0D;&#x540C;&#x7684;&#x5206;&#x9801;&#x4E2D;&#x7C21;&#x55AE;&#x7684;&#x5617;&#x8A66;&#x4E00;&#x4E0B;&#x5C31;&#x53EF;&#x4EE5;&#x767C;&#x73FE;&#xFF0C;&#x96D6;&#x7136;&#x5728;&#x540C;&#x4E00;&#x500B;&#x9801;&#x9762;&#x4E0A;&#x7684; localStorage &#x90FD;&#x53EF;&#x4EE5;&#x8DDF;&#x8457;&#x66F4;&#x65B0;&#x6C92;&#x932F;&#xFF0C;&#x4F46;&#x4E00;&#x9047;&#x5230;&#x4E86;&#x8DE8;&#x9801;&#x9762;&#x5C31;&#x7121;&#x6CD5;&#x81EA;&#x52D5;&#x66F4;&#x65B0;&#x4E86;&#x2026;&#x2026; &#x9019;&#x600E;&#x9EBC;&#x884C;&#xFF1F;localStorage &#x7684;&#x5176;&#x4E2D;&#x4E00;&#x500B;&#x597D;&#x8655;&#x5C31;&#x662F;&#x53EF;&#x4EE5;&#x8DE8;&#x9801;&#x9762;&#x5132;&#x5B58;&#x554A;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x80FD;&#x505A;&#x5230;&#x8DE8;&#x9801;&#x9762;&#x66F4;&#x65B0;&#x7684;&#x8A71;&#x4E0D;&#x5C31;&#x6C92;&#x6709;&#x4EC0;&#x9EBC;&#x610F;&#x7FA9;&#x4E86;&#x3002;</p>
<p>&#x6240;&#x4EE5;&#x6211;&#x5011;&#x63A5;&#x4E0B;&#x4F86;&#x8981;&#x9032;&#x884C;&#x6539;&#x826F;&#xFF0C;&#x5148;&#x5F9E;&#x5982;&#x4F55;&#x76E3;&#x807D;&#x66F4;&#x65B0;&#x958B;&#x59CB;&#xFF0C;Javascript &#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x500B;&#x65B9;&#x4FBF;&#x6211;&#x5011;&#x76E3;&#x807D; localStorage &#x5F9E;&#x5176;&#x4ED6;&#x9801;&#x9762;&#x66F4;&#x65B0;&#x4E86;&#x7684;&#x4E8B;&#x4EF6; &#x2014;&#x2014; <code>storage</code> &#x4E8B;&#x4EF6;<sup class="footnote-ref"><a href="#fn10" id="fnref10">[10]</a></sup>&#x3002;</p>
<pre><code class="language-javascript">window.addEventListener(&apos;storage&apos;, ({key, newValue}) =&gt; {
  if (key == &apos;num&apos;) {
    document.body.innerText = `num updates: ${newValue}`
  }
})
</code></pre>
<p class="codepen" data-height="140" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="QWyqmGr" style="height: 140px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="QWyqmGr">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/QWyqmGr?ref=blog.davy.tw">
  QWyqmGr</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<p>&#x6240;&#x4EE5;&#x6211;&#x5011;&#x53EA;&#x8981;&#x5728;&#x76E3;&#x807D;&#x5230;&#x4E8B;&#x4EF6;&#x4E4B;&#x5F8C;&#x585E;&#x9032;&#x53BB; <code>Vue.localStorage</code> &#x4E2D;&#x5C31;&#x597D;&#x4E86;&#x5C0D;&#x5427;&#xFF1F;&#x50CF;&#x9019;&#x6A23;&#xFF1A;</p>
<pre><code class="language-javascript">window.addEventListener(&apos;storage&apos;, ({key, newValue}) =&gt; {
  Vue.localStorage[key] = LocalStorage.unpack(newValue)
})
</code></pre>
<p class="codepen" data-height="150" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="XWXeEKQ" style="height: 150px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="XWXeEKQ">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/XWXeEKQ?ref=blog.davy.tw">
  XWXeEKQ</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<p>&#x5947;&#x602A;&#xFF0C;&#x70BA;&#x4EC0;&#x9EBC;&#x9084;&#x662F;&#x6C92;&#x6709;&#x9032;&#x884C;&#x66F4;&#x65B0;&#x554A;&#xFF1F;</p>
<p>&#x539F;&#x4F86;&#x662F; Vue &#x5728; Hook &#x7684; Setter &#x4E2D;&#x6709;&#x5224;&#x65B7;&#xFF0C;&#x5982;&#x679C;&#x8981;&#x585E;&#x9032;&#x53BB;&#x7684;&#x503C;&#x8DDF;&#x76EE;&#x524D;&#x7684;&#x503C;&#xFF08;&#x5F9E; Getter &#x53D6;&#x51FA;&#xFF09;&#x76F8;&#x540C;&#x7684;&#x8A71;&#xFF0C;&#x90A3;&#x9EBC;&#x70BA;&#x4E86;&#x6548;&#x80FD;&#x8003;&#x91CF;&#x800C;&#x4E0D;&#x6703;&#x9032;&#x884C;&#x91CD;&#x7E6A;<sup class="footnote-ref"><a href="#fn11" id="fnref11">[11]</a></sup>&#xFF0C;&#x800C;&#x5F9E; Getter &#x76F4;&#x63A5;&#x53D6;&#x51FA;&#x7684;&#x8A71;&#x5BE6;&#x969B;&#x4E0A;&#x662F;&#x6703;&#x53D6;&#x51FA;&#x76EE;&#x524D; localStorage &#x4E2D;&#x6700;&#x65B0;&#x7684;&#x503C;&#xFF08;&#x8207; <code>storage</code> &#x4E8B;&#x4EF6;&#x4E2D;&#x7684; <code>newValue</code> &#x76F8;&#x540C;&#xFF09;&#x5C0E;&#x81F4; Vue &#x4E0D;&#x6703;&#x9032;&#x884C;&#x66F4;&#x65B0;&#xFF1A;</p>
<pre><code class="language-javascript">// vue@2.6.11:src/core/observer/index.js
export function defineReactive (obj, key, ...) {
  // ...
  Object.defineProperty(obj, key, {
    // ...,
    set(newVal) {
      const value = getter ? getter.call(obj) : val
      if (newVal === value || (newVal !== newVal &amp;&amp; value !== value)) {
        return
      }
      // ...
    }
  })
}
</code></pre>
<p>&#x6240;&#x4EE5;&#x6211;&#x5011;&#x5FC5;&#x9808;&#x5F97;&#x5728;&#x524D;&#x9762;&#x518D;&#x589E;&#x52A0;&#x4E00;&#x5C64; Proxy &#x4F86;&#x8B93; Getter &#x4E0D;&#x6703;&#x53D6;&#x5F97; localStorage &#x4E2D;&#x6700;&#x65B0;&#x7684;&#x503C;&#xFF0C;&#x800C;&#x662F;&#x6700;&#x5F8C;&#x66F4;&#x65B0;&#x904E;&#x7684;&#x503C;&#x624D;&#x884C;&#xFF0C;&#x65BC;&#x662F;&#x6211;&#x5728;&#x9019;&#x88E1;&#x8A2D;&#x8A08;&#x4E86;&#x4E00;&#x500B; Cache &#x6A5F;&#x5236;&#xFF0C;&#x8B93;&#x6240;&#x6709;&#x6700;&#x5F8C;&#x5728;&#x9019;&#x500B;&#x9801;&#x9762;&#x4E0A;&#x66F4;&#x65B0;&#x904E;&#x7684;&#x5167;&#x5BB9;&#x90FD;&#x5BEB;&#x5165; Cache &#x4E2D;&#xFF0C;&#x8B80;&#x53D6;&#x6642;&#x4E5F;&#x6703;&#x76F4;&#x63A5;&#x5F9E; Cache &#x4E2D;&#x8B80;&#x53D6;&#xFF1A;</p>
<pre><code class="language-javascript">class LocalStorage {
  static createCache() {
    return new Proxy({}, {
      get(target, property, receiver) {
        if (!(property in target)) {
          target[property] = LocalStorage.unpack(window.localStorage.getItem(property))
        }
        
        return target[property]
      },
      set(target, property, value, receiver) {
        target[property] = value
        window.localStorage.setItem(property, LocalStorage.pack(value))
        
        return true
      },
    })
  }
}
</code></pre>
<p class="codepen" data-height="130" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="ZEQXoRp" style="height: 130px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="ZEQXoRp">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/ZEQXoRp?ref=blog.davy.tw">
  ZEQXoRp</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<p>&#x9019;&#x88E1;&#x4F7F;&#x7528;&#x4E86; Proxy API<sup class="footnote-ref"><a href="#fn12" id="fnref12">[12]</a></sup> &#x4F86;&#x6355;&#x6349;&#x6240;&#x6709;&#x7684; Get/Set Properties &#x884C;&#x70BA;&#xFF0C;&#x9019;&#x6A23;&#x5C31;&#x53EF;&#x4EE5;&#x4E0D;&#x7BA1;&#x5728; Cache &#x4E2D;&#x5BEB;&#x5165;&#x6216;&#x8B80;&#x53D6;&#x4EFB;&#x4F55;&#x503C;&#x90FD;&#x5B8C;&#x7F8E;&#x7684;&#x88AB;&#x6211;&#x5011; Hook &#x8D77;&#x4F86;&#x4E86;&#xFF0C;&#x5176;&#x5BE6;&#x5728; Vue 3 &#x4E2D;&#x4E5F;&#x662F;&#x653E;&#x68C4;&#x4E86; <code>Object.defineProperty</code> &#x800C;&#x6539;&#x7528; Proxy &#x4F86; Hook&#x3002;</p>
<h3 id>&#x52D5;&#x614B;&#x6B04;&#x4F4D;</h3>
<p>&#x65E2;&#x7136;&#x6211;&#x5011;&#x90FD;&#x4F7F;&#x7528;&#x4E86; Proxy &#x4F86;&#x5E6B;&#x6211;&#x5011;&#x6355;&#x6349;&#x5728; Cache &#x4E2D;&#x4EFB;&#x610F;&#x6B04;&#x4F4D;&#x7684;&#x8B8A;&#x5316;&#x4E86;&#xFF0C;&#x662F;&#x4E0D;&#x662F;&#x4E5F;&#x8868;&#x793A;&#x6211;&#x5011;&#x53EF;&#x4EE5;&#x7528;&#x4E00;&#x6A23;&#x7684;&#x65B9;&#x6CD5;&#x4F86;&#x8B93;&#x6211;&#x5011;&#x4E0D;&#x9700;&#x8981;&#x518D;&#x50B3;&#x905E;&#x4E00;&#x500B;&#x6B04;&#x4F4D;&#x6E05;&#x55AE;&#x5230;&#x6211;&#x5011;&#x7684; LocalStorage Plugin &#x4E86;&#x5462;&#xFF1F;</p>
<p>&#x6C92;&#x932F;&#xFF0C;&#x99AC;&#x4E0A;&#x5C31;&#x4F86;&#x8A66;&#x9A57;&#x4E00;&#x4E0B;&#xFF1A;</p>
<pre><code class="language-javascript">class LocalStorage {
  constructor(Vue) {
    // ...
    this.storage = new Proxy({}, {
      get(target, property, receiver) {
        if (!target.hasOwnProperty(property)) {
          observeItem(target, property)
        }
        return target[property]
      },
      set(target, property, value) {
        if (!target.hasOwnProperty(property)) {
          observeItem(target, property)
        }
        
        target[property] = value
        return true
      },
    })
  }
}
</code></pre>
<p class="codepen" data-height="400" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="WNrZJmv" style="height: 400px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="WNrZJmv">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/WNrZJmv?ref=blog.davy.tw">
  WNrZJmv</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<h3 id>&#x66F4;&#x597D;&#x7684;&#x52D5;&#x614B;&#x6B04;&#x4F4D;</h3>
<p>&#x5F88;&#x597D;&#xFF0C;&#x770B;&#x8D77;&#x4F86;&#x53EA;&#x6709;&#x88AB;&#x7528;&#x5230;&#x7684; <code>num</code> &#x6B04;&#x4F4D;&#x88AB;&#x8A18;&#x9304;&#x5728;&#x6211;&#x5011;&#x7684; LocalStorage Plugin &#x88E1;&#x9762;&#x4E86;&#x3002;</p>
<p>&#x54A6;&#xFF1F;&#x5947;&#x602A;&#xFF0C;&#x5982;&#x679C; localStorage &#x4E2D;&#x6709;&#x5176;&#x4ED6;&#x6B04;&#x4F4D;&#x800C;&#x6211;&#x5011;&#x537B;&#x9084;&#x6C92;&#x6709; Get &#x904E;&#x7684;&#x8A71;&#xFF0C;&#x5728; <code>Vue.localStorage</code> &#x88E1;&#x9762;&#x5C31;&#x6C92;&#x6709;&#x8FA6;&#x6CD5;&#x900F;&#x904E; <code>Object.keys</code>/<code>in</code>/<code>for-in</code> &#x7B49;&#x65B9;&#x6CD5;&#x9032;&#x884C;&#x904D;&#x6B77;&#x4E86;&#x2026;&#x2026; &#x9019;&#x6A23;&#x4E0D;&#x5C31;&#x8DDF;&#x6C92;&#x6709;&#x52D5;&#x614B;&#x6B04;&#x4F4D;&#x4E00;&#x6A23;&#x55CE;&#xFF1F;</p>
<p>&#x597D;&#x5728; Proxy API &#x63D0;&#x4F9B;&#x4E86;&#x66F4;&#x591A;&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x53EF;&#x4EE5;&#x8B93;&#x6211;&#x5011;&#x5C0D;&#x4E0A;&#x9762;&#x9019;&#x4E9B;&#x64CD;&#x4F5C;&#x9032;&#x884C; Hook&#xFF0C;&#x65BC;&#x662F;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x8457;&#x624B;&#x4FEE;&#x6539;&#x6210;&#x4E0B;&#x9762;&#x7684;&#x5F62;&#x5F0F;&#xFF1A;</p>
<pre><code class="language-javascript">class LocalStorage {
  constructor(Vue) {
    // ...
    this.storage = new Proxy({}, {
      get(target, property, receiver) {
        // &#x6211;&#x5011;&#x53EA; Hook string property key
        if (!target.hasOwnProperty(property) &amp;&amp; typeof property === &apos;string&apos;) {
          observeItem(target, property)
        }
        return target[property]
      },
      set(target, property, value) {
        // &#x6211;&#x5011;&#x53EA; Hook string property key
        if (!target.hasOwnProperty(property) &amp;&amp; typeof property === &apos;string&apos;) {
          observeItem(target, property)
        }
        
        target[property] = value
        return true
      },
      deleteProperty(target, property) {
        delete _cache[property]
        // Keep Vue tracking this property
        target[property] = undefined
        
        return true
      },
      ownKeys(target) {
        // &#x5F9E; window.localStorage &#x8B80;&#x53D6; keys
        return Reflect.ownKeys(window.localStorage)
      },
      getOwnPropertyDescriptor(target, property) {
        // &#x5F9E; windows.localStorage &#x8B80;&#x53D6; property descriptor
        return Reflect.getOwnPropertyDescriptor(window.localStorage, property)
      },
      has(target, property) {
        // &#x5224;&#x65B7; windows.localStorage &#x4E2D;&#x662F;&#x5426;&#x6709;&#x8A72; property
        return property in window.localStorage
      },
    })
  }
}
</code></pre>
<p class="codepen" data-height="340" data-theme-id="dark" data-default-tab="result" data-user="david50407" data-slug-hash="XWXeYWe" style="height: 340px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="XWXeYWe">
  <span>See the Pen <a href="https://codepen.io/david50407/pen/XWXeYWe?ref=blog.davy.tw">
  XWXeYWe</a> by David Kuo (<a href="https://codepen.io/david50407?ref=blog.davy.tw">@david50407</a>)
  on <a href="https://codepen.io/?ref=blog.davy.tw">CodePen</a>.</span>
</p>
<p>&#x5728; v-for &#x904D;&#x6B77;&#x7684;&#x6642;&#x5019;&#xFF0C;Vue &#x6703;&#x5617;&#x8A66;&#x53D6;&#x5F97; <code>vm.$localStorage[[Symbol.iterator]]</code> &#x5C0E;&#x81F4;&#x6211;&#x5011;&#x539F;&#x5148;&#x5BEB;&#x7684; get &#x6703;&#x5617;&#x8A66;&#x53BB;&#x76E3;&#x807D;&#x9019;&#x500B;&#x6771;&#x897F;&#xFF0C;&#x800C;&#x5C0E;&#x81F4;&#x6709;&#x932F;&#x8AA4;&#x88AB;&#x62CB;&#x51FA;&#xFF0C;&#x65BC;&#x662F;&#x9806;&#x4FBF;&#x4FEE;&#x6539;&#x4E00;&#x4E0B; Hook &#x7684;&#x898F;&#x5247;&#xFF0C;&#x6539;&#x6210;&#x53EA;&#x5C0D; string key property &#x53BB;&#x76E3;&#x807D;&#x3002;</p>
<p>&#x540C;&#x6642;&#xFF0C;&#x9019;&#x500B;&#x7BC4;&#x4F8B;&#x5176;&#x5BE6;&#x4E5F;&#x662F;&#x6211;&#x5011;&#x9019;&#x6B21;&#x7684;&#x5B8C;&#x6574;&#x7248;&#xFF0C;&#x9084;&#x5077;&#x5077;&#x52A0;&#x4E0A;&#x4E86;&#x652F;&#x63F4; delete &#x64CD;&#x4F5C;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x6709;&#x8208;&#x8DA3;&#x7684;&#x540C;&#x5B78;&#x5C31;&#x81EA;&#x5DF1;&#x53BB;&#x770B;&#x770B;&#x5427; XD</p>
<h2 id>&#x5F8C;&#x8A18;</h2>
<p>&#x5728;&#x7814;&#x7A76;&#x5982;&#x4F55;&#x5BE6;&#x4F5C;&#x4E00;&#x500B; Reactive &#x7684;&#x72C0;&#x614B;&#x4E26;&#x8207; localStorage &#x540C;&#x6B65;&#x7684;&#x904E;&#x7A0B;&#x4E2D;&#x4E5F;&#x662F;&#x7B2C;&#x4E00;&#x6B21;&#x5617;&#x8A66;&#x4E86; Proxy API &#x7684;&#x5BEB;&#x6CD5;&#xFF0C;&#x5176;&#x5BE6;&#x5BEB;&#x8D77;&#x4F86;&#x9084;&#x6EFF;&#x8212;&#x670D;&#x7684;&#xFF0C;&#x6709;&#x9EDE;&#x671F;&#x5F85; Vue 3 &#x7684;&#x66F4;&#x65B0;&#x4E86;&#x3002;</p>
<p>&#x5230;&#x6642;&#x5019;&#x61C9;&#x8A72;&#x6703;&#x628A;&#x672C;&#x6587;&#x5BEB;&#x7684; Plugin &#x5305;&#x6210;&#x4E00;&#x500B; package &#x4E1F;&#x5230; npm &#x4E0A;&#x9762;&#xFF0C;&#x5927;&#x5BB6;&#x4E5F;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x62FF;&#x4E0A;&#x9762;&#x7684;&#x7A0B;&#x5F0F;&#x78BC;&#x53BB;&#x73A9;&#x73A9;&#x770B;&#xFF0C;&#x6216;&#x662F;&#x4FEE;&#x6539;&#x6210;&#x7B26;&#x5408;&#x81EA;&#x5DF1;&#x7528;&#x9014;&#x7684; Plugin &#x9806;&#x4FBF;&#x7DF4;&#x7FD2;&#x770B;&#x770B;&#xFF01;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x5E38;&#x898B;&#x7684; MVC &#x524D;&#x7AEF;&#x6846;&#x67B6;&#xFF0C;&#x898B; <a href="https://vuejs.org/?ref=blog.davy.tw">Vue.js &#x5B98;&#x65B9;&#x7DB2;&#x7AD9;</a>&#x4EE5;&#x77AD;&#x89E3;&#x66F4;&#x591A;&#x3002; <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>&#x700F;&#x89BD;&#x5668;&#x4E2D;&#x7368;&#x6709;&#x7684; localStorage &#x529F;&#x80FD;&#xFF0C;&#x63D0;&#x4F9B;&#x7DB2;&#x9801;&#x524D;&#x7AEF;&#x5132;&#x5B58;&#x5C11;&#x8A31;&#x8CC7;&#x6599;&#x7684;&#x7A7A;&#x9593;&#xFF0C;&#x8A73;&#x898B; <a href="https://developer.mozilla.org/zh-TW/docs/Web/API/Window/localStorage?ref=blog.davy.tw">MDN &#x4E0A;&#x9762;&#x7684;&#x8AAA;&#x660E;</a>&#x3002; <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>&#x6709;&#x95DC; Vue &#x4E2D; Reactivity &#x7684;&#x904B;&#x4F5C;&#x6A5F;&#x5236;&#xFF0C;&#x53EF;&#x4EE5;&#x53C3;&#x898B; <a href="https://vuejs.org/v2/guide/reactivity.html?ref=blog.davy.tw">Vue &#x7DB2;&#x7AD9;&#x4E0A;&#x7684;&#x4ECB;&#x7D39;</a>&#x3002; <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>&#x6709;&#x95DC; <code>Object.defineProperty</code> &#x7684;&#x8AAA;&#x660E;&#xFF0C;&#x8ACB;&#x53C3;&#x898B; <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty?ref=blog.davy.tw">MDN &#x4E0A;&#x7684;&#x6587;&#x4EF6;</a>&#x3002; <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p>&#x6709;&#x95DC; Getter/Setter &#x7684;&#x8AAA;&#x660E;&#xFF0C;&#x8ACB;&#x53C3;&#x898B; <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Working_with_Objects?ref=blog.davy.tw#Defining_getters_and_setters">MDN &#x4E0A;&#x7684;&#x6587;&#x4EF6;</a>&#x3002; <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p>&#x539F;&#x59CB;&#x78BC;&#x8ACB;&#x898B; <a href="https://github.com/vuejs/vue/blob/v2.6.11/src/core/observer/index.js?ref=blog.davy.tw#L135">https://github.com/vuejs/vue/blob/v2.6.11/src/core/observer/index.js#L135</a> &#x3002; <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn7" class="footnote-item"><p>&#x6709;&#x95DC;&#x5982;&#x4F55;&#x64B0;&#x5BEB; Vue Plugin&#xFF0C;&#x5728; <a href="https://vuejs.org/v2/guide/plugins.html?ref=blog.davy.tw#Writing-a-Plugin">Vue &#x5B98;&#x7DB2;&#x4E0A;&#x6709;&#x4E00;&#x4E9B;&#x57FA;&#x790E;&#x7684;&#x7BC4;&#x4F8B;</a>&#x3002; <a href="#fnref7" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn8" class="footnote-item"><p>&#x6709;&#x95DC; <code>JSON.stringify</code> &#x7684;&#x7528;&#x6CD5;&#xFF0C;&#x8ACB;&#x898B; <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify?ref=blog.davy.tw">MDN &#x4E0A;&#x7684;&#x6587;&#x4EF6;&#x8AAA;&#x660E;</a>&#x3002; <a href="#fnref8" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn9" class="footnote-item"><p>&#x6709;&#x95DC; <code>JSON.parse</code> &#x7684;&#x7528;&#x6CD5;&#xFF0C;&#x8ACB;&#x898B; <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse?ref=blog.davy.tw">MDN &#x4E0A;&#x7684;&#x6587;&#x4EF6;&#x8AAA;&#x660E;</a>&#x3002; <a href="#fnref9" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn10" class="footnote-item"><p>&#x6709;&#x95DC; <code>storage</code> &#x4E8B;&#x4EF6;&#x7684;&#x8A73;&#x7D30;&#x8CC7;&#x8A0A;&#xFF0C;&#x53EF;&#x4EE5;&#x53C3;&#x8003; <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event?ref=blog.davy.tw">MDN &#x4E0A;&#x7684;&#x8AAA;&#x660E;</a>&#x3002; <a href="#fnref10" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn11" class="footnote-item"><p>&#x539F;&#x59CB;&#x78BC;&#x8ACB;&#x898B; <a href="https://github.com/vuejs/vue/blob/v2.6.11/src/core/observer/index.js?ref=blog.davy.tw#L176">https://github.com/vuejs/vue/blob/v2.6.11/src/core/observer/index.js#L176</a> &#x3002; <a href="#fnref11" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn12" class="footnote-item"><p>&#x6709;&#x95DC; Proxy &#x7684;&#x7528;&#x6CD5;&#xFF0C;&#x53EF;&#x4EE5;&#x53C3;&#x8003; <a href="https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Proxy?ref=blog.davy.tw">MDN &#x4E0A;&#x7684;&#x8AAA;&#x660E;</a>&#x3002; <a href="#fnref12" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[在 WSL2 裡面使用 GPU 加速機器學習]]></title><description><![CDATA[微軟在 Microsoft Build 2020 時曾表示，將在 WSL2 中新增支援 NVIDIA CUDA 以及 DirectML 來讓 Linux 中的機器學習應用可以無痛直接放到 WSL2 中使用。

沒想到才過一個月，微軟就在 Windows 10 Insider (20150+, WSL2 Kernel 4.19.121+) 釋出了支援 NVIDIA CUDA 以及 DirectML 的功能，目前 NVIDIA CUDA 看起來是直接跟 NVIDIA 合作並釋出驅動程式來支援在 WSL2 中的 GPU 虛擬化；而 DirectML 則是……]]></description><link>https://blog.davy.tw/posts/microsoft-annouced-gpu-accelerated-machine-learning-on-wsl2/</link><guid isPermaLink="false">5eec18bf8b52a70001c21fa6</guid><category><![CDATA[Windows]]></category><category><![CDATA[WSL]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Fri, 19 Jun 2020 01:56:31 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x5FAE;&#x8EDF;&#x5728; Microsoft Build 2020 &#x6642;&#x66FE;&#x8868;&#x793A;&#xFF0C;&#x5C07;&#x5728; WSL2 &#x4E2D;&#x65B0;&#x589E;&#x652F;&#x63F4; NVIDIA CUDA &#x4EE5;&#x53CA; DirectML &#x4F86;&#x8B93; Linux &#x4E2D;&#x7684;&#x6A5F;&#x5668;&#x5B78;&#x7FD2;&#x61C9;&#x7528;&#x53EF;&#x4EE5;&#x7121;&#x75DB;&#x76F4;&#x63A5;&#x653E;&#x5230; WSL2 &#x4E2D;&#x4F7F;&#x7528;&#x3002;</p>
<p>&#x6C92;&#x60F3;&#x5230;&#x624D;&#x904E;&#x4E00;&#x500B;&#x6708;&#xFF0C;&#x5FAE;&#x8EDF;&#x5C31;&#x5728; Windows 10 Insider (20150+, WSL2 Kernel 4.19.121+) &#x91CB;&#x51FA;&#x4E86;&#x652F;&#x63F4; NVIDIA CUDA &#x4EE5;&#x53CA; DirectML &#x7684;&#x529F;&#x80FD;&#xFF0C;&#x76EE;&#x524D; NVIDIA CUDA &#x770B;&#x8D77;&#x4F86;&#x662F;&#x76F4;&#x63A5;&#x8DDF; NVIDIA &#x5408;&#x4F5C;&#x4E26;&#x91CB;&#x51FA;&#x9A45;&#x52D5;&#x7A0B;&#x5F0F;&#x4F86;&#x652F;&#x63F4;&#x5728; WSL2 &#x4E2D;&#x7684; GPU &#x865B;&#x64EC;&#x5316;&#xFF1B;&#x800C; DirectML &#x5247;&#x662F;&#x8DDF; NVIDIA/AMD/Intel &#x5408;&#x4F5C;&#x91CB;&#x51FA;&#x9A45;&#x52D5;&#x7A0B;&#x5F0F;<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>&#xFF0C;&#x4E26;&#x5728; TensorFlow &#x4E0A;&#x9762;&#x5BE6;&#x4F5C;&#x4EE5; DirectML &#x70BA;&#x5F8C;&#x7AEF;&#x7684;&#x7248;&#x672C;&#xFF0C;&#x4E26;&#x5411;&#x4E0A;&#x6E38;&#x63D0;&#x4EA4;&#x4E86; Pull Request<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>&#x3002;</p>
<p>&#x6C92;&#x60F3;&#x5230;&#x5FAE;&#x8EDF;&#x52D5;&#x4F5C;&#x9019;&#x9EBC;&#x5FEB;&#xFF0C;&#x770B;&#x4F86;&#x662F;&#x771F;&#x7684;&#x6709;&#x5728; WSL2 &#x4E0A;&#x9762;&#x6295;&#x6CE8;&#x5F88;&#x591A;&#x8CC7;&#x6E90;&#x60F3;&#x8981;&#x978F;&#x56FA;&#x6574;&#x500B;&#x751F;&#x614B;&#x7CFB;&#xFF0C;&#x5C0D;&#x6211;&#x5011;&#x9019;&#x4E9B;&#x958B;&#x767C;&#x8005;&#x4F86;&#x8AAA;&#x5176;&#x5BE6;&#x4E5F;&#x662F;&#x633A;&#x597D;&#x7684;&#xFF0C;&#x9078;&#x64C7;&#x4E5F;&#x8B8A;&#x591A;&#x4E86;&#x3002;XD</p>
<p>ref: <a href="https://blogs.windows.com/windowsdeveloper/2020/06/17/gpu-accelerated-ml-training-inside-the-windows-subsystem-for-linux/?ref=blog.davy.tw">https://blogs.windows.com/windowsdeveloper/2020/06/17/gpu-accelerated-ml-training-inside-the-windows-subsystem-for-linux/</a><br>
ref: <a href="https://docs.microsoft.com/zh-tw/windows/win32/direct3d12/gpu-accelerated-training?ref=blog.davy.tw">https://docs.microsoft.com/zh-tw/windows/win32/direct3d12/gpu-accelerated-training</a></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x622A;&#x81F3;&#x672C;&#x6587;&#x767C;&#x6587;&#x6642;&#x9593;&#x70BA;&#x6B62;&#xFF0C;NVIDIA &#x50C5;&#x91CB;&#x51FA;&#x4E86;&#x53EF;&#x4F7F;&#x7528; CUDA &#x7684;&#x9A45;&#x52D5;&#xFF0C;&#x800C; DirectML &#x7684;&#x7248;&#x672C;&#x5247;&#x5C1A;&#x672A;&#x91CB;&#x51FA;&#x3002; <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="https://github.com/tensorflow/community/pull/243?ref=blog.davy.tw">https://github.com/tensorflow/community/pull/243</a> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[如何從 NSSDB (certutil) 中取出 pem 格式的 key]]></title><description><![CDATA[因為最近在玩 FreeIPA 的關係，會需要幫 https 服務簽署憑證，在理解如何使用 FreeIPA 簽署的同時，順便發現到了一個管理憑證與其金鑰的工具 —— certutil。

certutil 可以管理 NSS Database 裡面的憑證與金鑰，FreeIPA 中的 PKI 服務 Dogtag 亦使用此一工具來管理憑證，就連 Firefox 自有的憑證庫也是使用這個方式儲存。不過，雖然這個 toolset 很棒，但我的 https 服務只吃 pem 格式的憑證，但從 NSSDB 取出的金鑰則會是 p12格式，這裡需要再做一些人工的轉換]]></description><link>https://blog.davy.tw/posts/how-to-extract-pem-format-key-from-nssdb-certutil/</link><guid isPermaLink="false">5e70e55a8b52a70001c21e0f</guid><category><![CDATA[FreeIPA]]></category><category><![CDATA[NSSDB]]></category><category><![CDATA[certutil]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Tue, 17 Mar 2020 16:51:48 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>&#x672C;&#x7BC7;&#x63D0;&#x5230;&#x7684; certutil &#x7CFB;&#x6307; UNIX &#x7CFB;&#x7D71;&#x4E0B;&#x7684; Certificate Database &#x7BA1;&#x7406;&#x5DE5;&#x5177;&#xFF0C;&#x8207; Windows Server &#x7684; certutil &#x7121;&#x95DC;&#xFF0C;&#x82E5;&#x60F3;&#x4E86;&#x89E3; Windows Server &#x4E0B;&#x7684; certutil&#xFF0C;&#x8ACB;&#x9020;&#x8A2A;&#xFF1A; <a href="https://docs.microsoft.com/zh-tw/windows-server/administration/windows-commands/certutil?ref=blog.davy.tw">https://docs.microsoft.com/zh-tw/windows-server/administration/windows-commands/certutil</a></p>
</blockquote>
<p>&#x56E0;&#x70BA;&#x6700;&#x8FD1;&#x5728;&#x73A9; FreeIPA &#x7684;&#x95DC;&#x4FC2;&#xFF0C;&#x6703;&#x9700;&#x8981;&#x5E6B; https &#x670D;&#x52D9;&#x7C3D;&#x7F72;&#x6191;&#x8B49;&#xFF0C;&#x5728;&#x7406;&#x89E3;&#x5982;&#x4F55;&#x4F7F;&#x7528; FreeIPA &#x7C3D;&#x7F72;&#x7684;&#x540C;&#x6642;&#xFF0C;&#x9806;&#x4FBF;&#x767C;&#x73FE;&#x5230;&#x4E86;&#x4E00;&#x500B;&#x7BA1;&#x7406;&#x6191;&#x8B49;&#x8207;&#x5176;&#x91D1;&#x9470;&#x7684;&#x5DE5;&#x5177; &#x2014;&#x2014; certutil<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>&#x3002;</p>
<p>certutil &#x53EF;&#x4EE5;&#x7BA1;&#x7406; NSS Database &#x88E1;&#x9762;&#x7684;&#x6191;&#x8B49;&#x8207;&#x91D1;&#x9470;&#xFF0C;FreeIPA &#x4E2D;&#x7684; PKI &#x670D;&#x52D9; Dogtag &#x4EA6;&#x4F7F;&#x7528;&#x6B64;&#x4E00;&#x5DE5;&#x5177;&#x4F86;&#x7BA1;&#x7406;&#x6191;&#x8B49;&#xFF0C;&#x5C31;&#x9023; Firefox &#x81EA;&#x6709;&#x7684;&#x6191;&#x8B49;&#x5EAB;&#x4E5F;&#x662F;&#x4F7F;&#x7528;&#x9019;&#x500B;&#x65B9;&#x5F0F;&#x5132;&#x5B58;&#x3002;&#x4E0D;&#x904E;&#xFF0C;&#x96D6;&#x7136;&#x9019;&#x500B; toolset &#x5F88;&#x68D2;&#xFF0C;&#x4F46;&#x6211;&#x7684; https &#x670D;&#x52D9;&#x53EA;&#x5403; pem &#x683C;&#x5F0F;&#x7684;&#x6191;&#x8B49;&#xFF0C;&#x4F46;&#x5F9E; NSSDB &#x53D6;&#x51FA;&#x7684;&#x91D1;&#x9470;&#x5247;&#x6703;&#x662F; p12<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x683C;&#x5F0F;&#xFF0C;&#x9019;&#x88E1;&#x9700;&#x8981;&#x518D;&#x505A;&#x4E00;&#x4E9B;&#x4EBA;&#x5DE5;&#x7684;&#x8F49;&#x63DB;&#xFF0C;&#x6240;&#x4EE5;&#x9019;&#x88E1;&#x7B46;&#x8A18;&#x4E00;&#x4E0B;&#x8A72;&#x5982;&#x4F55;&#x4F7F;&#x7528;&#x9019;&#x4E9B;&#x5DE5;&#x5177;&#x9806;&#x4FBF;&#x7C21;&#x55AE;&#x4ECB;&#x7D39;&#x4E00;&#x4E0B;&#x5F9E; FreeIPA &#x4E0A;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#x7684;&#x6D41;&#x7A0B;&#x5427;&#x3002;</p>
<h2 id="nssdbca">&#x5EFA;&#x7ACB; NSSDB &#x4E26;&#x653E;&#x5165; CA</h2>
<p>&#x5728;&#x8DDF; FreeIPA &#x8ACB;&#x6C42;&#x6191;&#x8B49;&#x7C3D;&#x7F72;&#x4E4B;&#x524D;&#xFF0C;&#x6211;&#x5011;&#x8981;&#x5148;&#x6709;&#x81EA;&#x5DF1;&#x7684;&#x91D1;&#x9470;&#x5EAB;&#xFF0C;&#x6240;&#x4EE5;&#x6211;&#x5011;&#x8981;&#x5148;&#x900F;&#x904E; <code>certutil</code> &#x4F86;&#x5EFA;&#x7ACB;&#x91D1;&#x9470;&#x5EAB;&#x4E26;&#x5148;&#x532F;&#x5165;&#x6211;&#x5011;&#x7684; CA &#x6191;&#x8B49;&#xFF0C;&#x5148;&#x5047;&#x8A2D;&#x6211;&#x5011;&#x8981;&#x628A; NSSDB &#x5B58;&#x653E;&#x5728; <code>~/certs</code>&#xFF1A;</p>
<pre><code class="language-shell">$ mkdir -p ~/certs
$ certutil -N -d ~/certs # &#x5EFA;&#x7ACB;&#x65B0;&#x7684; NSSDB
$ certutil -A -d ~/certs -n &apos;IPA CA&apos; -t CT,, -a &lt; ca.crt # &#x532F;&#x5165; CA &#x6191;&#x8B49;
</code></pre>
<p><code>certutil</code> &#x7684;&#x6307;&#x4EE4;&#x8AAA;&#x660E;&#x53EF;&#x4EE5;&#x53BB;&#x53C3;&#x8003;&#x4F7F;&#x7528;&#x624B;&#x518A;&#xFF0C;&#x9019;&#x88E1;&#x53EA;&#x6703;&#x89E3;&#x91CB;&#x6709;&#x7528;&#x5230;&#x7684;&#x90E8;&#x5206;&#xFF1A;</p>
<ul>
<li><code>-d</code> &#x6307;&#x5B9A; NSSDB &#x4F4D;&#x7F6E;</li>
<li><code>-N</code> &#x5EFA;&#x7ACB;&#x65B0;&#x7684; NSSDB</li>
<li><code>-A</code> &#x532F;&#x5165;&#x5DF2;&#x5B58;&#x5728;&#x7684;&#x6191;&#x8B49;
<ul>
<li><code>-n</code> &#x7D66;&#x4E88;&#x8A72;&#x6191;&#x8B49;&#x4E00;&#x500B;&#x66B1;&#x7A31;&#xFF08;&#x6B64;&#x4F8B;&#x70BA; <code>IPA CA</code>&#xFF09;</li>
<li><code>-t</code> &#x8A2D;&#x5B9A;&#x8A72;&#x6191;&#x8B49;&#x7684;&#x4FE1;&#x4EFB;&#x6A21;&#x5F0F;&#xFF0C;&#x9019;&#x88E1;&#x6211;&#x5011;&#x63A1;&#x53D6;&#x4FE1;&#x4EFB;&#x8A72; CA &#x7C3D;&#x7F72;&#x7684;&#x4EFB;&#x4F55; Server/Client SSL</li>
<li><code>-a</code> &#x63A1; ASCII &#x7DE8;&#x78BC;&#x8F38;&#x5165;/&#x51FA;</li>
</ul>
</li>
</ul>
<h2 id>&#x5EFA;&#x7ACB;&#x91D1;&#x9470;&#x53CA;&#x6191;&#x8B49;&#x7C3D;&#x7F72;&#x8ACB;&#x6C42;</h2>
<p>&#x6709;&#x4E86;&#x81EA;&#x5DF1;&#x7684;&#x91D1;&#x9470;&#x5EAB;&#x4E4B;&#x5F8C;&#xFF0C;&#x5C31;&#x662F;&#x8981;&#x7522;&#x751F;&#x91D1;&#x9470;&#x53CA;&#x6191;&#x8B49;&#x7C3D;&#x7F72;&#x8ACB;&#x6C42;&#xFF08;Certificate Request&#xFF09;&#x4E86;&#xFF0C;&#x900F;&#x904E; <code>certutil</code> &#x6211;&#x5011;&#x53EF;&#x4EE5;&#x4E00;&#x6B65;&#x540C;&#x6642;&#x7522;&#x751F;&#x5169;&#x8005;&#xFF1A;</p>
<pre><code class="language-shell">$ certutil -R -d ~/certs -a -g 4096 -s CN=web.example.com,O=EXAMPLE.COM &gt; web.csr
</code></pre>
<ul>
<li><code>-R</code> &#x7522;&#x751F;&#x4E00;&#x500B;&#x6191;&#x8B49;&#x7C3D;&#x7F72;&#x8ACB;&#x6C42;&#x6A94;&#xFF08;<code>.csr</code>&#xFF09;
<ul>
<li><code>-g</code> &#x91D1;&#x9470;&#x9577;&#x5EA6;&#xFF0C;&#x9810;&#x8A2D;&#x70BA; <code>1024</code>&#xFF08;&#x6B64;&#x4F8B;&#x70BA; <code>4096</code>&#xFF09;</li>
<li><code>-s</code> &#x4E3B;&#x9AD4;&#x540D;&#x7A31;&#xFF08;Subject&#xFF09;&#xFF0C;&#x6B64;&#x8655;&#x9700;&#x586B;&#x5BEB;&#x6B64;&#x6191;&#x8B49;&#x7684; Common Name&#xFF08;&#x901A;&#x5E38;&#x662F; FQDN&#xFF09;&#xFF0C;&#x4EE5;&#x53CA; FreeIPA &#x8981;&#x6C42;&#x9700;&#x586B;&#x5BEB; Organization</li>
</ul>
</li>
</ul>
<blockquote>
<p>&#x82E5;&#x9700;&#x8981;&#x52A0;&#x5165; SAN<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup>&#xFF0C;&#x53EF;&#x4EE5;&#x518D;&#x52A0;&#x4E0A; <code>--extSAN</code> &#x53C3;&#x6578;&#xFF0C;&#x4F8B;&#x5982; <code>--extSAN dns:web.example.com,dns:web.example.org</code></p>
</blockquote>
<h2 id="freeipa">&#x5F9E; FreeIPA &#x7C3D;&#x767C;&#x6191;&#x8B49;</h2>
<p>&#x5F9E; FreeIPA &#x7C3D;&#x767C;&#x7684;&#x90E8;&#x5206;&#x53EF;&#x4EE5;&#x5F9E; Web UI &#x6216; CLI &#x5EFA;&#x7ACB;&#xFF0C;&#x9019;&#x908A;&#x5169;&#x8005;&#x90FD;&#x6703;&#x4ECB;&#x7D39;&#xFF0C;&#x8ACB;&#x8B80;&#x8005;&#x81EA;&#x5DF1;&#x9078;&#x64C7;&#x81EA;&#x5DF1;&#x559C;&#x6B61;&#x7684;&#x65B9;&#x5F0F;&#xFF1A;</p>
<h3 id="viacli">via CLI</h3>
<pre><code class="language-shell">$ kinit admin # &#x5148;&#x767B;&#x5165;&#x6709;&#x6B0A;&#x9650;&#x7C3D;&#x767C;&#x6191;&#x8B49;&#x7684; IPA &#x5E33;&#x865F;
Password for admin@EXAMPLE.COM:
$ ipa cert-request --principal=HTTP/web.example.com web.csr
Issuing CA: ipa
Certificate: ...
Subject: CN=web.example.com,O=EXAMPLE.COM
Issuer: CN=Certificate Authority,O=EXAMPLE.COM
Not Before: Wed Mar 18 00:00:00 2020 UTC
Not After: Thu Mar 17 00:00:00 2022 UTC
Serial number: 11 # &lt;= &#x8A18;&#x4E0B;&#x5E8F;&#x865F;
Serial number (hex): 0xB
$ ipa cert-show 11 --out=web.crt # &#x586B;&#x5165;&#x5E8F;&#x865F;&#xFF08;11&#xFF09;
Issuing CA: ipa
Certificate: ...
Subject: CN=web.example.com,O=EXAMPLE.COM
Issuer: CN=Certificate Authority,O=EXAMPLE.COM
Not Before: Wed Mar 18 00:00:00 2020 UTC
Not After: Sat Mar 19 00:00:00 2022 UTC
Serial number: 11
Serial number (hex): 0xB
Revoked: False
</code></pre>
<ul>
<li><code>ipa cert-request</code> &#x7C3D;&#x7F72;&#x6191;&#x8B49;
<ul>
<li><code>--principal</code> IPA &#x4E2D;&#x7684; Kerberos &#x4E3B;&#x9AD4;</li>
</ul>
</li>
<li><code>ipa cert-show</code> &#x53D6;&#x5F97;&#x5C0D;&#x61C9;&#x5E8F;&#x865F;&#x4E4B;&#x6191;&#x8B49;</li>
</ul>
<p>&#x53D6;&#x5F97;&#x6191;&#x8B49;&#x5F8C;&#xFF0C;&#x6211;&#x5011;&#x63A5;&#x4E0B;&#x4F86;&#x5C31;&#x662F;&#x8981;&#x6E96;&#x5099;&#x53D6;&#x5F97; pem &#x683C;&#x5F0F;&#x7684;&#x91D1;&#x9470;&#x4E86;&#x3002;</p>
<h3 id="viawebui">via Web UI</h3>
<p>&#x9996;&#x5148;&#x627E;&#x5230;&#x6211;&#x5011;&#x8981;&#x7C3D;&#x7F72;&#x7684;&#x670D;&#x52D9;&#xFF08;<code>HTTP/web.example.com</code>&#xFF09;&#xFF0C;&#x7136;&#x5F8C;&#x6309;&#x4E0B; Service Certificate &#x4E2D;&#x7684; Add&#xFF0C;&#x4E26;&#x586B;&#x5165;&#x525B;&#x525B;&#x7522;&#x751F;&#x7684; csr &#x5167;&#x5BB9;&#xFF1A;</p>
<p><img src="https://i.imgur.com/0pkmYNr.png" alt loading="lazy"><br>
<img src="https://i.imgur.com/yYlq9NX.png" alt loading="lazy"></p>
<p>&#x63A5;&#x4E0B;&#x4F86;&#x5C0D;&#x525B;&#x525B;&#x7522;&#x751F;&#x7684; Certificate &#x6309;&#x4E0B; Actions -&gt; Get&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x53D6;&#x5F97;&#x525B;&#x525B;&#x7522;&#x751F;&#x7684;&#x6191;&#x8B49;&#xFF0C;&#x6211;&#x5011;&#x5148;&#x8907;&#x88FD;&#x4E0B;&#x4F86;&#x4E26;&#x5132;&#x5B58;&#x5230; <code>web.crt</code>&#xFF0C;&#x7136;&#x5F8C;&#x5C31;&#x53EF;&#x4EE5;&#x6E96;&#x5099;&#x53D6;&#x5F97; pem &#x683C;&#x5F0F;&#x7684;&#x91D1;&#x9470;&#x4E86;&#x3002;</p>
<p><img src="https://i.imgur.com/6MFxKLR.png" alt loading="lazy"><br>
<img src="https://i.imgur.com/skGMArq.png" alt loading="lazy"></p>
<h2 id="pem">&#x53D6;&#x5F97; pem &#x683C;&#x5F0F;&#x91D1;&#x9470;</h2>
<p>&#x7D42;&#x65BC;&#x8981;&#x9032;&#x5165;&#x672C;&#x7BC7;&#x4E3B;&#x984C;&#x4E86; &#x2014;&#x2014; &#x53D6;&#x5F97; NSSDB &#x4E2D;&#x7684;&#x91D1;&#x9470;&#xFF0C;&#x9019;&#x88E1;&#x6211;&#x5011;&#x9084;&#x6703;&#x9700;&#x8981; NSS Security Tools &#x88E1;&#x7684;&#x53E6;&#x4E00;&#x500B;&#x5DE5;&#x5177; <code>pk12util</code><sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>&#xFF0C;&#x4ED6;&#x8CA0;&#x8CAC;&#x5C07; NSSDB &#x4E2D;&#x7684;&#x6191;&#x8B49;&#x53CA;&#x91D1;&#x9470;&#x4EE5; p12 &#x7684;&#x683C;&#x5F0F;&#x532F;&#x5165;/&#x532F;&#x51FA;&#xFF0C;&#x6211;&#x5011;&#x7A0D;&#x5F8C;&#x8981;&#x5229;&#x7528;&#x4ED6;&#x532F;&#x51FA; p12 &#x683C;&#x5F0F;&#x7684;&#x91D1;&#x9470;&#x4E26;&#x8F49;&#x6210; pem &#x683C;&#x5F0F;&#x3002;</p>
<h3 id>&#x532F;&#x5165;&#x7C3D;&#x767C;&#x6191;&#x8B49;</h3>
<p>&#x5728;&#x53D6;&#x5F97;&#x91D1;&#x9470;&#x4E4B;&#x524D;&#xFF0C;&#x6211;&#x5011;&#x5FC5;&#x9808;&#x5148;&#x532F;&#x5165;&#x525B;&#x525B;&#x53D6;&#x5F97;&#x7684;&#x6191;&#x8B49;&#xFF0C;&#x8B93; NSSDB &#x77E5;&#x9053;&#x6211;&#x5011;&#x6709;&#x4E00;&#x500B;&#x6191;&#x8B49;&#x5C0D;&#x61C9;&#x5230;&#x525B;&#x525B;&#x7522;&#x751F;&#x7684;&#x91D1;&#x9470;&#xFF0C;&#x4E4B;&#x5F8C;&#x6211;&#x5011;&#x624D;&#x53EF;&#x4EE5;&#x5C07;&#x91D1;&#x9470;&#x53D6;&#x51FA;&#xFF1A;</p>
<pre><code class="language-shell">$ certutil -A -d ~/certs -n web -t u,u,u -i web.crt
</code></pre>
<ul>
<li><code>-A</code> &#x532F;&#x5165;&#x5DF2;&#x5B58;&#x5728;&#x7684;&#x6191;&#x8B49;
<ul>
<li><code>-n</code> &#x7D66;&#x4E88;&#x8A72;&#x6191;&#x8B49;&#x4E00;&#x500B;&#x66B1;&#x7A31;&#xFF08;&#x6B64;&#x4F8B;&#x70BA; <code>web</code>&#xFF09;</li>
<li><code>-t</code> &#x8A2D;&#x5B9A;&#x8A72;&#x6191;&#x8B49;&#x7684;&#x4FE1;&#x4EFB;&#x6A21;&#x5F0F;&#xFF0C;&#x9019;&#x88E1;&#x6211;&#x5011;&#x4FE1;&#x4EFB;&#x8A72;&#x6191;&#x8B49;&#x4F5C;&#x70BA;&#x9A57;&#x8B49;&#x53CA;&#x7C3D;&#x7AE0;&#x7528;</li>
<li><code>-i</code> &#x6191;&#x8B49;&#x6A94;&#x540D;</li>
</ul>
</li>
</ul>
<h3 id="p12">&#x53D6;&#x51FA; p12 &#x91D1;&#x9470;</h3>
<p>&#x6210;&#x529F;&#x532F;&#x5165;&#x6191;&#x8B49;&#x4E4B;&#x5F8C;&#x6211;&#x5011;&#x5C31;&#x53EF;&#x4EE5;&#x4F7F;&#x7528; <code>pk12util</code> &#x5C07;&#x91D1;&#x9470;&#x532F;&#x51FA;&#x4E86;&#xFF1A;</p>
<pre><code class="language-shell">$ pk12util -d ~/certs -n web -o web.p12
</code></pre>
<p><code>pk12util</code> &#x7684;&#x53C3;&#x6578;&#x5927;&#x81F4;&#x4E0A;&#x90FD;&#x8DDF; <code>certutil</code> &#x5DEE;&#x4E0D;&#x591A;&#xFF0C;&#x57F7;&#x884C;&#x5B8C;&#x7562;&#x5F8C;&#x6703;&#x5F97;&#x5230;&#x4E00;&#x500B; p12 &#x683C;&#x5F0F;&#x7684;&#x91D1;&#x9470; <code>web.p12</code>&#x3002;</p>
<h3 id="pem">&#x8F49;&#x63DB;&#x6210; pem &#x91D1;&#x9470;</h3>
<p>&#x8F49;&#x63DB;&#x7684;&#x6B65;&#x9A5F;&#x4E5F;&#x5F88;&#x7C21;&#x55AE;&#xFF0C;&#x900F;&#x904E;&#x842C;&#x80FD;&#x7684; OpenSSL &#x5C31;&#x53EF;&#x4EE5;&#x8F49;&#x63DB;&#x4E86;&#xFF1A;</p>
<pre><code class="language-shell">$ openssl pkcs12 -in web.p12 -out web.key -nocerts -nodes
</code></pre>
<p>&#x7D93;&#x904E;&#x8F49;&#x63DB;&#x5F8C;&#x7684; pem &#x683C;&#x5F0F;&#x91D1;&#x9470;&#x6703;&#x88AB;&#x5B58;&#x653E;&#x5728; <code>web.key</code> &#x4E2D;&#xFF0C;&#x5982;&#x679C;&#x6253;&#x958B;&#x4F86;&#x770B;&#x7684;&#x8A71;&#x6703;&#x767C;&#x73FE;&#x9664;&#x4E86;&#x91D1;&#x9470;&#x672C;&#x9AD4;&#xFF0C;&#x9084;&#x6703;&#x9644;&#x4E0A;&#x4E00;&#x4E9B;&#x984D;&#x5916;&#x8CC7;&#x8A0A;&#x5982;&#x4E0B;&#xFF0C;&#x5982;&#x679C;&#x662F;&#x8981;&#x62FF;&#x53BB;&#x7D66;&#x670D;&#x52D9;&#x5403;&#x7684;&#x8A71;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x522A;&#x6389;&#x7559;&#x4E0B;&#x91D1;&#x9470;&#x672C;&#x9AD4;&#x5373;&#x53EF;&#xFF1A;</p>
<pre><code class="language-pem">Tag Attributes
    friendlyName: web
    localKeyID: ...
Key Attributes: &lt;No Attributes&gt;
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
</code></pre>
<h2 id>&#x5F8C;&#x8A18;</h2>
<p>&#x4E4B;&#x524D;&#x6709;&#x767C;&#x904E;&#x4E00;&#x7BC7;&#x95DC;&#x65BC;&#x4F7F;&#x7528; OpenSSL &#x4F86;&#x7C3D;&#x767C;&#x4E2D;&#x4ECB; CA &#x7684;&#x65B9;&#x6CD5;&#xFF0C;&#x9019;&#x6B21;&#x6539;&#x5617;&#x8A66;&#x4F7F;&#x7528;&#x4E0D;&#x540C;&#x7684;&#x5DE5;&#x5177;&#x4F86;&#x64CD;&#x4F5C;&#x6191;&#x8B49;&#xFF0C;&#x7562;&#x7ADF;&#x9054;&#x5230;&#x76F8;&#x540C;&#x76EE;&#x7684;&#x7684;&#x5DE5;&#x5177;&#x767E;&#x767E;&#x7A2E;&#xFF0C;&#x591A;&#x7528;&#x4E00;&#x4E9B;&#x6293;&#x5230;&#x81EA;&#x5DF1;&#x6700;&#x9806;&#x624B;&#x7684;&#x65B9;&#x5F0F;&#x53CA;&#x5DE5;&#x5177;&#x53EF;&#x4EE5;&#x5927;&#x5927;&#x7684;&#x63D0;&#x5347;&#x5DE5;&#x4F5C;&#x6548;&#x7387;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x8208;&#x8DA3;&#x4F7F;&#x7528; NSSDB &#x7BA1;&#x7406;&#x6191;&#x8B49;&#x53CA;&#x91D1;&#x9470;&#x7684;&#x670B;&#x53CB;&#x5011;&#x53EF;&#x4EE5;&#x591A;&#x8A66;&#x8A66;&#x770B;&#xFF0C;&#x771F;&#x7684;&#x6EFF;&#x65B9;&#x4FBF;&#x7684;&#xFF0C;&#x91D1;&#x9470;&#x518D;&#x4E5F;&#x4E0D;&#x6703;&#x4E82;&#x4E1F;&#x4E86; XDDDD</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x4E00;&#x500B;&#x5728; UNIX &#x7CFB;&#x7D71;&#x4E0B;&#x7BA1;&#x7406; Certificate Database &#x7684;&#x5DE5;&#x5177;&#xFF0C;&#x5C6C;&#x65BC; NSS Security Tools &#x7684;&#x4E00;&#x90E8;&#x5206;&#xFF0C;&#x5728; Debian/Ubuntu &#x4E0B;&#x5957;&#x4EF6;&#x540D;&#x70BA; <code>libnss3-tools</code>&#xFF1B;RHEL/Fedora/CentOS &#x4E0B;&#x5247;&#x70BA; <code>nss-tools</code>&#x3002;&#x4F7F;&#x7528;&#x8AAA;&#x660E;&#x53EF;&#x4EE5;&#x53C3;&#x8003; <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/tools/NSS_Tools_certutil?ref=blog.davy.tw">MDN</a> &#x6216; <a href="https://www.systutorials.com/docs/linux/man/1-certutil/?ref=blog.davy.tw">man 1 certutil</a>&#x3002; <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>PKCS #12&#xFF0C;&#x5B58;&#x653E;&#x91D1;&#x9470;&#x53CA;&#x6191;&#x8B49;&#x7684;&#x4E00;&#x7A2E;&#x683C;&#x5F0F;&#xFF0C;&#x5E38;&#x898B;&#x526F;&#x6A94;&#x540D;&#x6709; <code>.p12</code> &#x53CA; <code>.pfx</code>&#xFF0C;&#x8A73;&#x898B;&#x7DAD;&#x57FA;&#x767E;&#x79D1;&#x4E0A;&#x7684;&#x300A;<a href="https://zh.wikipedia.org/zh-tw/PKCS_12?ref=blog.davy.tw">PKCS 12</a>&#x300B;&#x689D;&#x76EE; <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>Subject Alternative Name&#xFF0C;&#x70BA; X.509 extension &#x7684;&#x4E00;&#x90E8;&#x5206;&#xFF0C;&#x652F;&#x63F4;&#x55AE;&#x4E00;&#x6191;&#x8B49;&#x64F4;&#x5145;&#x63CF;&#x8FF0;&#x66FF;&#x4EE3;&#x7528;&#x7684;&#x4E3B;&#x9AD4;&#x540D;&#x7A31;&#xFF0C;&#x53EF;&#x7528;&#x4F86;&#x8B93;&#x6191;&#x8B49;&#x652F;&#x63F4;&#x591A;&#x500B; domain&#x3002; <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>&#x4F7F;&#x7528;&#x8AAA;&#x660E;&#x53EF;&#x4EE5;&#x53C3;&#x8003; <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/tools/NSS_Tools_pk12util?ref=blog.davy.tw">MDN</a> &#x6216; <a href="https://www.systutorials.com/docs/linux/man/1-pk12util/?ref=blog.davy.tw">man 1 pk12util</a>&#x3002; <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[npm 被 GitHub 併購了]]></title><description><![CDATA[npm, Inc.（就是維護 npm registry 的那間公司）宣布被 GitHub 買下來了，registry 還是會一樣免費且開放的提供給大家]]></description><link>https://blog.davy.tw/posts/npm-is-accquired-by-github/</link><guid isPermaLink="false">5e6fc2c18b52a70001c21df2</guid><category><![CDATA[GitHub]]></category><category><![CDATA[npm]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Mon, 16 Mar 2020 18:21:27 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>npm, Inc.&#xFF08;&#x5C31;&#x662F;&#x7DAD;&#x8B77; npm registry &#x7684;&#x90A3;&#x9593;&#x516C;&#x53F8;&#xFF09;&#x5BA3;&#x5E03;&#x88AB; GitHub &#x8CB7;&#x4E0B;&#x4F86;&#x4E86;<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup><sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>&#xFF0C;registry &#x9084;&#x662F;&#x6703;&#x4E00;&#x6A23;&#x514D;&#x8CBB;&#x4E14;&#x958B;&#x653E;&#x7684;&#x63D0;&#x4F9B;&#x7D66;&#x5927;&#x5BB6;&#x3002;</p>
<p>&#x8981;&#x7DAD;&#x6301;&#x4E00;&#x9593; startup &#x9700;&#x8981;&#x6709;&#x5F88;&#x5927;&#x7684;&#x6BC5;&#x529B;&#xFF0C;&#x56E0;&#x70BA;&#x4E0D;&#x53EA;&#x516C;&#x53F8;&#x7684;&#x904B;&#x4F5C;&#x3001;&#x65B9;&#x5411;&#x9084;&#x6709;&#x8CC7;&#x91D1;&#x4F86;&#x6E90;&#x7B49;&#xFF0C;&#x90FD;&#x662F;&#x5F88;&#x5927;&#x7684;&#x8AB2;&#x984C;&#xFF0C;&#x5FC5;&#x9808;&#x6642;&#x6642;&#x523B;&#x523B;&#x628A;&#x5FC3;&#x529B;&#x653E;&#x5728;&#x4E0A;&#x9762;&#xFF0C;&#x525B;&#x597D; GitHub &#x4E5F;&#x6709;&#x610F;&#x7DAD;&#x904B;&#x81EA;&#x5DF1;&#x7684; package registry&#xFF0C;&#x9019;&#x5C0D; npm &#x4F86;&#x8AAA;&#x662F;&#x4E00;&#x500B;&#x5927;&#x597D;&#x7684;&#x6A5F;&#x6703; &#x2014;&#x2014; &#x4E00;&#x500B;&#x628A;&#x81EA;&#x5DF1;&#x51FA;&#x6389;&#xFF0C;&#x8A17;&#x4ED8;&#x7D66;&#x4E00;&#x500B;&#x6709;&#x76EE;&#x6A19;&#x4E14;&#x5C0D; Open Source &#x6587;&#x5316;&#x6709;&#x5BE6;&#x8CEA;&#x8CA2;&#x737B;&#x8DDF;&#x7406;&#x60F3;&#x7684;&#x6A5F;&#x6703;&#x3002;</p>
<p>npm, Inc. &#x96D6;&#x7136;&#x88AB;&#x8CB7;&#x4E0B;&#x4F86;&#x4E86;&#xFF0C;&#x4F46;&#x4ED6;&#x5E36;&#x7D66;&#x5927;&#x5BB6;&#x7684;&#x74B0;&#x5883;&#x8DDF;&#x98A8;&#x6C23;&#x537B;&#x6703;&#x88AB;&#x7559;&#x4E0B;&#x4F86;&#xFF0C;&#x5E0C;&#x671B; GitHub &#x63A5;&#x624B;&#x4E4B;&#x5F8C;&#x53EF;&#x4EE5;&#x628A; npm registry &#x904B;&#x4F5C;&#x7684;&#x66F4;&#x597D;&#x3001;&#x66F4;&#x5B8C;&#x7F8E;&#x3002;</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x539F;&#x6587;&#x5728;&#x6B64;&#xFF1A; <a href="https://blog.npmjs.org/post/612764866888007680/next-phase-montage?ref=blog.davy.tw">The npm Blog - Next Phase Montage</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>GitHub &#x4EA6;&#x5728;&#x5176;&#x90E8;&#x843D;&#x683C;&#x767C;&#x8868;&#x8072;&#x660E; <a href="https://github.blog/2020-03-16-npm-is-joining-github/?ref=blog.davy.tw">npm is joining GitHub - The GitHub blog</a> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[如何將 Rancher 串上 FreeIPA 驗證]]></title><description><![CDATA[因工作需求，最近在研究如何使用 Rancher 來管理 Kubernetes 叢集，於是打算在 Homelab 上也建一組，想說前幾個禮拜還在研究 FreeIPA 乾脆把他們湊一堆好了 XD]]></description><link>https://blog.davy.tw/posts/how-to-configure-rancher-auth-with-freeipa/</link><guid isPermaLink="false">5e6cadeae95ecd00019bd986</guid><category><![CDATA[Rancher]]></category><category><![CDATA[FreeIPA]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Sat, 14 Mar 2020 11:12:21 GMT</pubDate><content:encoded><![CDATA[<p>&#x56E0;&#x5DE5;&#x4F5C;&#x9700;&#x6C42;&#xFF0C;&#x6700;&#x8FD1;&#x5728;&#x7814;&#x7A76;&#x5982;&#x4F55;&#x4F7F;&#x7528; Rancher<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> &#x4F86;&#x7BA1;&#x7406; Kubernetes<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> &#x53E2;&#x96C6;&#xFF0C;&#x65BC;&#x662F;&#x6253;&#x7B97;&#x5728; Homelab &#x4E0A;&#x4E5F;&#x5EFA;&#x4E00;&#x7D44;&#xFF0C;&#x60F3;&#x8AAA;&#x524D;&#x5E7E;&#x500B;&#x79AE;&#x62DC;&#x9084;&#x5728;&#x7814;&#x7A76; FreeIPA<sup class="footnote-ref"><a href="#fn3" id="fnref3">[3]</a></sup> &#x4E7E;&#x8106;&#x628A;&#x4ED6;&#x5011;&#x6E4A;&#x4E00;&#x5806;&#x597D;&#x4E86; XD</p>
<h2 id="%E6%BA%96%E5%82%99-service-account">&#x6E96;&#x5099; Service Account</h2>
<p>&#x5728;&#x958B;&#x59CB;&#x5C07; FreeIPA &#x9A57;&#x8B49;&#x63A5;&#x9032; Rancher &#x4E4B;&#x524D;&#xFF0C;Rancher &#x8981;&#x6C42;&#x5148;&#x5728; IPA &#x88E1;&#x9762;&#x5EFA;&#x7ACB;&#x4E00;&#x500B; Service Account &#x4F86;&#x63D0;&#x4F9B; Rancher &#x67E5;&#x8A62; Domain &#x4E0B;&#x7684;&#x4F7F;&#x7528;&#x8005;&#x8207;&#x7FA4;&#x7D44;&#xFF0C;&#x4F46;&#x9019;&#x500B;&#x5EFA;&#x7ACB; Service Account &#x7684;&#x6B65;&#x9A5F;&#x7121;&#x6CD5;&#x5F9E; FreeIPA Web &#x754C;&#x9762;&#x57F7;&#x884C;&#xFF0C;&#x5FC5;&#x9808;&#x624B;&#x52D5;&#x5C07;&#x9019;&#x500B; Account &#x52A0;&#x5165; LDAP &#x4E2D;<sup class="footnote-ref"><a href="#fn4" id="fnref4">[4]</a></sup>&#xFF0C;&#x9996;&#x5148;&#x5230; IPA master &#x4E0A;&#x57F7;&#x884C;&#x4E0B;&#x5217;&#x6B65;&#x9A5F;&#xFF1A;&#xFF08;&#x5047;&#x8A2D; IPA domain &#x70BA; <code>example.com</code>&#xFF09;</p>
<pre><code class="language-shell">$ cat - &lt;&lt;-EOF &gt; add-srvacct-rancher.ldif
dn: uid=rancher,cn=sysaccounts,cn=etc,dc=example,dc=com
changetype: add
objectclass: account
objectclass: simplesecurityobject
uid: rancher
userPassword: 2Brq/Ux4rs:2Dnt3#%Rx
nsIdleTimeout: 0
EOF
$ ldapmodify -x -D &apos;cn=Directory Manager&apos; -W &lt; add-srvacct-rancher.ldif
Enter LDAP Password: # Enter Dircetory Manager password
adding new entry &quot;uid=rancher,cn=sysaccounts,cn=etc,dc=example,dc=com&quot;
$
</code></pre>
<p>&#x5176;&#x4E2D; <code>dc=example,dc=com</code> &#x8A18;&#x5F97;&#x63DB;&#x6210;&#x81EA;&#x5DF1;&#x7684; IPA domain&#xFF0C;&#x4EE5;&#x53CA;&#x81EA;&#x5DF1;&#x7522;&#x751F; <code>userPassword</code>&#xFF08;&#x7B46;&#x8005;&#x662F;&#x4F7F;&#x7528;&#x5BC6;&#x78BC;&#x7522;&#x751F;&#x5668;&#x7522;&#x751F;&#xFF09;&#x5F8C;&#x8A18;&#x4E0B;&#xFF0C;&#x5F85;&#x6703;&#x6703;&#x5728; Rancher &#x8A2D;&#x5B9A;&#x7528;&#x5230;&#x3002;</p>
<h2 id="%E8%A8%AD%E5%AE%9A-rancher">&#x8A2D;&#x5B9A; Rancher</h2>
<p>&#x9996;&#x5148;&#x767B;&#x5165;&#x6709; administrator &#x6B0A;&#x9650;&#x7684;&#x5E33;&#x865F;&#xFF0C;&#x4E26;&#x4F9D;&#x7167;&#x4EE5;&#x4E0B;&#x6B65;&#x9A5F;&#x8A2D;&#x5B9A; FreeIPA Authenticate&#xFF1A;</p>
<ol>
<li>&#x5728; Global &#x57DF;&#x4E2D;&#x9078;&#x64C7; Security -&gt; Authentication<br>
<img src="https://i.imgur.com/8hMk8fD.png" alt loading="lazy"></li>
<li>&#x9078;&#x64C7; FreeIPA<br>
<img src="https://i.imgur.com/Yj1GEEk.png" alt loading="lazy"></li>
<li>&#x586B;&#x5165; FreeIPA &#x4F3A;&#x670D;&#x5668;&#x8CC7;&#x8A0A;</li>
<li>&#x5728; Service Account &#x76F8;&#x95DC;&#x8CC7;&#x8A0A;&#x4E2D;&#x586B;&#x5165;&#x525B;&#x525B;&#x5EFA;&#x7ACB;&#x7684; Service Account
<ul>
<li>Service Account Distinguished Name&#xFF08;&#x8A18;&#x5F97;&#x63DB;&#x6210; IPA domain&#xFF09;
<ul>
<li><code>uid=rancher,cn=sysaccounts,cn=etc,dc=example,dc=com</code></li>
</ul>
</li>
<li>Service Account Password
<ul>
<li>&#x525B;&#x525B;&#x5EFA;&#x7ACB;&#x7684; <code>userPassword</code> &#x503C;</li>
</ul>
</li>
</ul>
</li>
<li>&#x586B;&#x5165;&#x4F7F;&#x7528;&#x8005;&#x8CC7;&#x6599;&#x5EAB;&#x76F8;&#x95DC;&#x8CC7;&#x8A0A;
<ul>
<li>User Search Base&#xFF08;&#x8A18;&#x5F97;&#x63DB;&#x6210; IPA domain&#xFF09;
<ul>
<li><code>cn=users,cn=accounts,dc=example,dc=com</code></li>
</ul>
</li>
<li>Group Search Base&#xFF08;&#x8A18;&#x5F97;&#x63DB;&#x6210; IPA domain&#xFF09;
<ul>
<li><code>cn=groups,cn=accounts,dc=example,dc=com</code></li>
</ul>
</li>
</ul>
</li>
<li>Customize Schema &#x7684;&#x90E8;&#x5206;&#x6211;&#x6703;&#x9078;&#x64C7;&#x8ABF;&#x6574;&#x4F7F;&#x7528;&#x8005;&#x7684;&#x5E33;&#x865F;&#x8CC7;&#x8A0A;&#x5C0D;&#x61C9;
<ul>
<li>Username Attribute&#xFF08;&#x4F7F;&#x7528;&#x8005;&#x986F;&#x793A;&#x540D;&#x7A31;&#xFF09;
<ul>
<li><code>displayName</code></li>
</ul>
</li>
<li>Login Attribute&#xFF08;&#x4F7F;&#x7528;&#x8005;&#x5E33;&#x865F;&#xFF09;
<ul>
<li><code>uid</code></li>
</ul>
</li>
<li>Search Attribute&#xFF08;&#x641C;&#x5C0B;&#x6B04;&#x4F4D;&#xFF0C;&#x5728;&#x641C;&#x5C0B;&#x4F7F;&#x7528;&#x8005;&#x6642;&#x6703;&#x53BB;&#x5C0B;&#x627E;&#x7684;&#x6B04;&#x4F4D;&#xFF0C;&#x9810;&#x8A2D;&#x662F;&#x59D3;&#x540D;&#x8DDF;&#x5E33;&#x865F;&#xFF09;
<ul>
<li><code>uid</code></li>
</ul>
</li>
</ul>
</li>
<li>&#x5728; Test and enable authentication &#x4E2D;&#x586B;&#x5165;&#x8981;&#x8207;&#x76EE;&#x524D;&#x5E33;&#x865F;&#x7D81;&#x5B9A;&#x7684; FreeIPA &#x5E33;&#x865F;&#x8CC7;&#x8A0A;
<ul>
<li>&#x6839;&#x64DA; Rancher &#x7684;&#x8AAA;&#x660E;<sup class="footnote-ref"><a href="#fn5" id="fnref5">[5]</a></sup>&#xFF0C;&#x5728;&#x9019;&#x88E1;&#x586B;&#x5165;&#x7684; FreeIPA &#x5E33;&#x865F;&#xFF08;external principal&#xFF09;&#x6703;&#x81EA;&#x52D5;&#x5C0D;&#x61C9;&#x5230;&#x76EE;&#x524D;&#x7528;&#x4F86;&#x8A2D;&#x5B9A;&#x7684;&#x7BA1;&#x7406;&#x54E1;&#x5E33;&#x865F;&#xFF08;local principal&#xFF09;&#xFF0C;&#x4E26;&#x6703;&#x5728;&#x8A2D;&#x5B9A;&#x6210;&#x529F;&#x4E4B;&#x5F8C;&#x81EA;&#x52D5;&#x6539;&#x7528; external principal &#x767B;&#x5165; Rancher</li>
</ul>
</li>
<li>&#x5728;&#x8A2D;&#x5B9A;&#x5B8C;&#x6210;&#x5F8C;&#x9EDE;&#x64CA; Authenticate with FreeIPA &#x5373;&#x53EF;&#x5B8C;&#x6210;&#x8A2D;&#x5B9A;</li>
</ol>
<p>&#x8A2D;&#x5B9A;&#x5B8C;&#x6210;&#x5F8C;&#x767C;&#x73FE;&#x6703;&#x88AB; Rancher &#x81EA;&#x52D5;&#x4EE5;&#x525B;&#x525B; test authentication &#x7684;&#x5E33;&#x865F;&#x767B;&#x5165;&#xFF0C;&#x4E26;&#x4E14;&#x540C;&#x6642;&#x53C8;&#x662F;&#x525B;&#x525B;&#x8A2D;&#x5B9A;&#x6642;&#x4F7F;&#x7528;&#x7684;&#x7BA1;&#x7406;&#x54E1;&#x5E33;&#x865F;&#xFF0C;&#x5F9E; Preference &#x9801;&#x9762;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x9019;&#x500B;&#x73FE;&#x8C61;&#xFF0C;&#x4F46;&#x4E0D;&#x8981;&#x7DCA;&#x5F35;&#xFF0C;&#x53EA;&#x662F;&#x56E0;&#x70BA; Rancher &#x628A;&#x9019;&#x5169;&#x500B;&#x5E33;&#x865F;&#x7D81;&#x5B9A;&#x4E86;&#xFF0C;&#x5171;&#x7528; local ID&#x3002;<br>
<img src="https://i.imgur.com/dJTepcN.png" alt loading="lazy"></p>
<h2 id="%E5%BE%8C%E8%A8%98">&#x5F8C;&#x8A18;</h2>
<p>&#x9019;&#x6B21;&#x7684;&#x7BC7;&#x5E45;&#x7A0D;&#x77ED;&#xFF0C;&#x4ECB;&#x7D39;&#x7684;&#x5167;&#x5BB9;&#x4E5F;&#x662F;&#x504F;&#x7C21;&#x55AE;&#xFF0C;&#x50C5;&#x5C0D;&#x65BC; FreeIPA &#x5982;&#x4F55;&#x5EFA;&#x7ACB; Service Account &#x7684;&#x90E8;&#x5206;&#x6709;&#x7279;&#x5225;&#x9700;&#x8981;&#x64B0;&#x5BEB; ldif &#x4F86;&#x624B;&#x52D5;&#x52A0;&#x5165; LDAP&#x3002; &#x4E0D;&#x77E5;&#x9053;&#x5927;&#x5BB6;&#x5C0D;&#x65BC;&#x9019;&#x7A2E;&#x7BC7;&#x5E45;&#x53CA;&#x985E;&#x578B;&#x7684;&#x6587;&#x7AE0;&#x63A5;&#x53D7;&#x5EA6;&#x5982;&#x4F55;&#xFF0C;&#x5C31;&#x5148;&#x7576;&#x4F5C;&#x662F;&#x5617;&#x8A66;&#x770B;&#x770B;&#xFF0C;&#x540C;&#x6642;&#x4E5F;&#x662F;&#x5728;&#x56DE;&#x61C9;&#x7B46;&#x8005;&#x670B;&#x53CB;&#x517C;&#x5927;&#x795E; &#x5C0F;&#x98DB;&#x6A5F; &#x63D0;&#x51FA;&#x7684;&#x770B;&#x6CD5;<sup class="footnote-ref"><a href="#fn6" id="fnref6">[6]</a></sup>&#x300C;&#x8CC7;&#x8A0A;&#x592A;&#x591A;&#xFF0C;&#x900F;&#x904E;&#x6587;&#x5B57;&#x6D88;&#x5316;&#x8CC7;&#x8A0A;&#x548C;&#x6574;&#x7406;&#x601D;&#x7DD2;&#x300D;&#x4E26;&#x70BA;&#x81EA;&#x5DF1;&#x800C;&#x5BEB;&#xFF0C;&#x56E0;&#x6B64;&#x6253;&#x7B97;&#x958B;&#x59CB;&#x5617;&#x8A66;&#x9019;&#x7A2E;<s>&#x5EE2;&#x6587;&#x9AD4;</s>&#x77ED;&#x7BC7;&#x7B46;&#x8A18;&#x578B;&#x7684;&#x5167;&#x5BB9;&#xFF0C;&#x540C;&#x6642;&#x7528;&#x6BD4;&#x8F03;&#x8F15;&#x9B06;&#x7684;&#x614B;&#x5EA6;&#x4F86;&#x767C;&#x6587;&#x770B;&#x770B; XD</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>&#x7BA1;&#x7406; Kubernetes &#x53E2;&#x96C6;&#x7684;&#x5DE5;&#x5177;&#xFF0C;&#x63D0;&#x4F9B;&#x591A;&#x53E2;&#x96C6;&#x3001;ACL&#x3001;&#x81EA;&#x52D5;&#x90E8;&#x7F72;&#x3001;Web &#x754C;&#x9762;&#x7B49;&#x7279;&#x9EDE;&#xFF0C;&#x8A72;&#x516C;&#x53F8;&#x9084;&#x6709;&#x51FA;&#x5F88;&#x591A; K8s &#x76F8;&#x95DC;&#x7684;&#x5176;&#x4ED6;&#x5DE5;&#x5177;&#xFF0C;&#x8A73;&#x898B;<a href="https://rancher.com/?ref=blog.davy.tw">&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>Kubernetes &#x662F;&#x7528;&#x65BC;&#x81EA;&#x52D5;&#x90E8;&#x7F72;&#x3001;&#x64F4;&#x5C55;&#x548C;&#x7BA1;&#x7406;&#x300C;&#x5BB9;&#x5668;&#x5316;&#xFF08;containerized&#xFF09;&#x61C9;&#x7528;&#x7A0B;&#x5F0F;&#x300D;&#x7684;&#x958B;&#x6E90;&#x7CFB;&#x7D71;&#xFF0C;&#x8A73;&#x898B;&#x5176;<a href="https://kubernetes.io/?ref=blog.davy.tw">&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;</a> <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn3" class="footnote-item"><p>FreeIPA &#x662F;&#x514D;&#x8CBB;&#x7684;&#x958B;&#x6E90;&#x8EAB;&#x4EFD;&#x7BA1;&#x7406;&#x7CFB;&#x7D71;&#xFF0C;IPA &#x5206;&#x5225;&#x4EE3;&#x8868; Identity&#x3001;Policy&#x3001;Audit&#xFF0C;&#x540C;&#x6642;&#x4E5F;&#x662F; Red Hat Identity Manager &#x7684;&#x4E0A;&#x6E38;&#x958B;&#x6E90;&#x5C08;&#x6848;&#xFF0C;&#x8A73;&#x898B;&#x5176;<a href="https://www.freeipa.org/page/Main_Page?ref=blog.davy.tw">&#x5B98;&#x65B9;&#x7DB2;&#x7AD9;</a> <a href="#fnref3" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn4" class="footnote-item"><p>FreeIPA &#x7684; <a href="https://www.freeipa.org/page/HowTo/LDAP?ref=blog.davy.tw#System_Accounts">HowTo/LDAP &#x9801;&#x9762;</a>&#x4EA6;&#x6709;&#x63D0;&#x53CA;&#x5982;&#x4F55;&#x65B0;&#x589E; Service Account/System Account <a href="#fnref4" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn5" class="footnote-item"><p><a href="https://rancher.com/docs/rancher/v2.x/en/admin-settings/authentication/?ref=blog.davy.tw#external-authentication-configuration-and-principal-users">https://rancher.com/docs/rancher/v2.x/en/admin-settings/authentication/#external-authentication-configuration-and-principal-users</a> <a href="#fnref5" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn6" class="footnote-item"><p>&#x8ACB;&#x898B;&#x5C0F;&#x98DB;&#x6A5F;&#x5927;&#x5927;&#x7684;&#x6587;&#x7AE0;&#x300A;<a href="https://blog.pichuang.com.tw/20200308-technical-writer/?ref=blog.davy.tw">&#x6210;&#x70BA;&#x4E00;&#x540D;&#x6280;&#x8853;&#x7559;&#x8DE1;&#x8005;</a>&#x300B; <a href="#fnref6" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
]]></content:encoded></item><item><title><![CDATA[FreeNAS 要跟 TrueNAS 合併了]]></title><description><![CDATA[同是 iXsystems 的 FreeNAS 要跟 TrueNAS 在名稱上統一了，改用 TrueNAS CORE/TrueNAS Enterprise 來取代原本 FreeNAS/TrueNAS 的名稱。

這個變動最快可以在 12.0 版本上看到，iX 還提到許多合併的好處：包含加速開發時程（從年更到半年更）、減少 QA 成本、跟 Upstream OS 跟更緊、簡化重複的文件、方便在兩個版本直接轉換等。兩者除了品牌合併之外，預計也會做到除了版本名稱不同，其 codebase 也會完全共享。]]></description><link>https://blog.davy.tw/posts/freenas-and-truenas-are-unifying/</link><guid isPermaLink="false">5e65eb7ee95ecd00019bd932</guid><category><![CDATA[FreeNAS]]></category><category><![CDATA[TrueNAS]]></category><dc:creator><![CDATA[Davy]]></dc:creator><pubDate>Mon, 09 Mar 2020 07:24:10 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x540C;&#x662F; iXsystems &#x7684; FreeNAS &#x8981;&#x8DDF; TrueNAS &#x5728;&#x540D;&#x7A31;&#x4E0A;&#x7D71;&#x4E00;&#x4E86;&#xFF0C;&#x6539;&#x7528; TrueNAS CORE/TrueNAS Enterprise &#x4F86;&#x53D6;&#x4EE3;&#x539F;&#x672C; FreeNAS/TrueNAS &#x7684;&#x540D;&#x7A31;&#x3002;</p>
<p>&#x9019;&#x500B;&#x8B8A;&#x52D5;&#x6700;&#x5FEB;&#x53EF;&#x4EE5;&#x5728; 12.0 &#x7248;&#x672C;&#x4E0A;&#x770B;&#x5230;&#xFF0C;iX &#x9084;&#x63D0;&#x5230;&#x8A31;&#x591A;&#x5408;&#x4F75;&#x7684;&#x597D;&#x8655;&#xFF1A;&#x5305;&#x542B;&#x52A0;&#x901F;&#x958B;&#x767C;&#x6642;&#x7A0B;&#xFF08;&#x5F9E;&#x5E74;&#x66F4;&#x5230;&#x534A;&#x5E74;&#x66F4;&#xFF09;&#x3001;&#x6E1B;&#x5C11; QA &#x6210;&#x672C;&#x3001;&#x8DDF; Upstream OS &#x8DDF;&#x66F4;&#x7DCA;&#x3001;&#x7C21;&#x5316;&#x91CD;&#x8907;&#x7684;&#x6587;&#x4EF6;&#x3001;&#x65B9;&#x4FBF;&#x5728;&#x5169;&#x500B;&#x7248;&#x672C;&#x76F4;&#x63A5;&#x8F49;&#x63DB;&#x7B49;&#x3002;&#x5169;&#x8005;&#x9664;&#x4E86;&#x54C1;&#x724C;&#x5408;&#x4F75;&#x4E4B;&#x5916;&#xFF0C;&#x9810;&#x8A08;&#x4E5F;&#x6703;&#x505A;&#x5230;&#x9664;&#x4E86;&#x7248;&#x672C;&#x540D;&#x7A31;&#x4E0D;&#x540C;&#xFF0C;&#x5176; codebase &#x4E5F;&#x6703;&#x5B8C;&#x5168;&#x5171;&#x4EAB;&#xFF08;iX &#x63D0;&#x5230;&#x5728; 11.3 &#x6642;&#x5169;&#x8005; codebase &#x5DF2;&#x7D93;&#x6709; 95% &#x91CD;&#x8907;&#xFF09;&#x3002;</p>
<p>&#x53E6;&#x5916; 12.0 &#x9084;&#x9810;&#x671F;&#x53EF;&#x4EE5;&#x770B;&#x5230; Open ZFS 2.0 &#x7684;&#x8E64;&#x5F71;&#xFF0C;&#x81EA;&#x5F9E; FreeBSD &#x5BA3;&#x4F48;&#x8981;&#x5408;&#x4F75; ZFS &#x5230; Open ZFS &#x5C31;&#x4E00;&#x76F4;&#x5F88;&#x4EE4;&#x4EBA;&#x671F;&#x5F85;&#xFF0C;iX &#x4E5F;&#x6295;&#x5165;&#x4E0D;&#x5C11;&#x8CC7;&#x6E90;&#x5230; Open ZFS &#x4E0A;&#x3002;</p>
<p>ref: <a href="https://www.ixsystems.com/blog/freenas-truenas-unification/?ref=blog.davy.tw">https://www.ixsystems.com/blog/freenas-truenas-unification/</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>