-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
213 lines (126 loc) · 126 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>hydaiの空想世界</title>
<link href="https://hyd.ai/atom.xml" rel="self"/>
<link href="https://hyd.ai/"/>
<updated>2024-12-13T10:41:57.678Z</updated>
<id>https://hyd.ai/</id>
<author>
<name>hydai</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>在 DigitalOcean 上部署 Flatcar Container Linux + LLM</title>
<link href="https://hyd.ai/2024/12/12/deploy-flatcar-on-do/"/>
<id>https://hyd.ai/2024/12/12/deploy-flatcar-on-do/</id>
<published>2024-12-12T14:31:17.000Z</published>
<updated>2024-12-13T10:41:57.678Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>之前在 Flatcar 的系統擴充元件提了<a href="https://github.com/flatcar/sysext-bakery/pulls?q=is:pr+author:hydai+is:closed">兩個 PRs</a>,讓 <a href="https://github.com/WasmEdge/WasmEdge/">WasmEdge</a> 與 <a href="https://github.com/LlamaEdge/LlamaEdge">LlamaEdge</a> 能以 sysext 的方式在 Flatcar 被部署時,一起被安裝在裡頭。因為跟 DigitalOcean 發生了一些事,因此決定留下筆記以後,準備遷移到 Azure 或其他友善的平台。</p><p>本文將涵蓋:</p><ol><li>如何建立屬於你的 Flatcar Sysext(系統擴充元件)。</li><li>如何在 DigitalOcean 上新增 Flatcar Container Linux 的客製化映像檔案。</li><li>如何在 DigitalOcean 上部署 Flatcar Container Linux。</li><li>如何執行 Wasm 的應用程式(利益揭露,我是 WasmEdge 的維護者)。</li><li>如何部署大語言模型(LLM)在 Flatcar Container Linux 上,使用 LlamaEdge 為例。(利益揭露,這個專案會編譯成 Wasm 格式,並執行在 WasmEdge 之上)。</li></ol><span id="more"></span><h2 id="為什麼選-Flatcar-Container-Linux"><a href="#為什麼選-Flatcar-Container-Linux" class="headerlink" title="為什麼選 Flatcar Container Linux?"></a>為什麼選 Flatcar Container Linux?</h2><p>Flatcar Container Linux 是 CoreOS Container Linux 的後繼者,是一個專為容器化應用程式所設計的作業系統。它的特點是:</p><ul><li>安全:無法使用套件管理系統進行修改,只能透過 sysext 進行擴充。</li><li>針對容器做最佳化:預設只有提供與執行容器相關的套件。減少安裝多餘套件導致被攻擊的機會增加。</li><li>方便的初始化設定:透過 <a href="https://coreos.github.io/ignition/">Ignition</a> 進行初始化設定,讓使用者可以在啟動時就完成想要的初始化設定,包含但不限於:啟動服務、在根檔案系統中建立檔案、重新格式化 <code>/var</code> 檔案系統、使用遠端的設定檔來取代原先的設定檔、新增使用者、修改內核參數等。</li></ul><p>友人 H 表示:「上面太官腔了,說實話好嗎?」<br>我:「實話就是我想把 WasmEdge Sysext 貢獻到 Flatcar 的生態系裡面,當然非選他不可<code>ψ(`∇´)ψ</code>」</p><h2 id="建立你的-Flatcar-系統擴充元件-Sysext"><a href="#建立你的-Flatcar-系統擴充元件-Sysext" class="headerlink" title="建立你的 Flatcar 系統擴充元件 (Sysext)"></a>建立你的 Flatcar 系統擴充元件 (Sysext)</h2><p>Flatcar 官方提供了一個工具 <a href="https://github.com/flatcar/sysext-bakery">sysext-bakery</a>,讓使用者可以建立自己的 sysext 。<br>上面有許多的範例:WasmEdge、Wasmtime、containerd、crio、kubernetes、nvidia-runtime 等等。應有盡有,可以從裡面選喜歡或者類似的為範本來進行修改。</p><h3 id="以-WasmEdge-為例"><a href="#以-WasmEdge-為例" class="headerlink" title="以 WasmEdge 為例"></a>以 WasmEdge 為例</h3><p>整個腳本可以分為以下幾個部分:</p><ol><li>設定 bash 的環境變數。</li><li>檢查參數是否正確,如果不正確就印出使用說明。</li><li>下載與安裝你需要的應用程式。在這個範例中,我們下載了 WasmEdge 的壓縮檔。</li><li>移動檔案到正確的位置,比如執行檔應放置於 <code>/usr/bin/</code> 下,函式庫應放置於 <code>/usr/lib/</code> 下等 。</li><li>執行 <code>bake.sh</code> 來建立 sysext。</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/env bash</span></span><br><span class="line"><span class="built_in">set</span> -euo pipefail</span><br><span class="line"></span><br><span class="line"><span class="comment"># 設定環境變數</span></span><br><span class="line"><span class="built_in">export</span> ARCH=<span class="string">"<span class="variable">${ARCH-x86-64}</span>"</span></span><br><span class="line">SCRIPTFOLDER=<span class="string">"<span class="subst">$(dirname <span class="string">"<span class="subst">$(readlink -f <span class="string">"<span class="variable">$0</span>"</span>)</span>"</span>)</span>"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 檢查參數</span></span><br><span class="line"><span class="keyword">if</span> [ <span class="variable">$#</span> -lt 2 ] || [ <span class="string">"<span class="variable">$1</span>"</span> = <span class="string">"-h"</span> ] || [ <span class="string">"<span class="variable">$1</span>"</span> = <span class="string">"--help"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="comment"># 列印使用說明</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Usage: <span class="variable">$0</span> VERSION SYSEXTNAME"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"The script will download the WasmEdge release tar ball (e.g., for 0.14.1) and create a sysext squashfs image with the name SYSEXTNAME.raw in the current folder."</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"A temporary directory named SYSEXTNAME in the current folder will be created and deleted again."</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"All files in the sysext image will be owned by root."</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"To use arm64 pass 'ARCH=arm64' as environment variable (current value is '<span class="variable">${ARCH}</span>')."</span></span><br><span class="line"> <span class="string">"<span class="variable">${SCRIPTFOLDER}</span>"</span>/bake.sh --<span class="built_in">help</span></span><br><span class="line"> <span class="built_in">exit</span> 1</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 從參數中取得版本號與 sysext 名稱</span></span><br><span class="line">VERSION=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line">SYSEXTNAME=<span class="string">"<span class="variable">$2</span>"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 由於 GitHub release 將會使用不同的硬體架構識別碼,需要在此進行轉換</span></span><br><span class="line"><span class="comment"># amd64 或 x86-64 皆改為 x86_64</span></span><br><span class="line"><span class="comment"># arm64 改為 aarch64</span></span><br><span class="line"><span class="comment"># The github release uses different arch identifiers, we map them here</span></span><br><span class="line"><span class="comment"># and rely on bake.sh to map them back to what systemd expects</span></span><br><span class="line"><span class="keyword">if</span> [ <span class="string">"<span class="variable">${ARCH}</span>"</span> = <span class="string">"amd64"</span> ] || [ <span class="string">"<span class="variable">${ARCH}</span>"</span> = <span class="string">"x86-64"</span> ]; <span class="keyword">then</span></span><br><span class="line"> ARCH=<span class="string">"x86_64"</span></span><br><span class="line"><span class="keyword">elif</span> [ <span class="string">"<span class="variable">${ARCH}</span>"</span> = <span class="string">"arm64"</span> ]; <span class="keyword">then</span></span><br><span class="line"> ARCH=<span class="string">"aarch64"</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 下載並解壓縮 WasmEdge</span></span><br><span class="line"><span class="built_in">rm</span> -f <span class="string">"WasmEdge-<span class="variable">${VERSION}</span>.tar.gz"</span></span><br><span class="line">curl -o <span class="string">"WasmEdge-<span class="variable">${VERSION}</span>.tar.gz"</span> -fsSL <span class="string">"https://github.com/WasmEdge/WasmEdge/releases/download/<span class="variable">${VERSION}</span>/WasmEdge-<span class="variable">${VERSION}</span>-ubuntu20.04_<span class="variable">${ARCH}</span>.tar.gz"</span></span><br><span class="line"><span class="built_in">rm</span> -rf <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span></span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span></span><br><span class="line">tar --force-local -xvf <span class="string">"WasmEdge-<span class="variable">${VERSION}</span>.tar.gz"</span> -C <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span></span><br><span class="line"><span class="built_in">rm</span> <span class="string">"WasmEdge-<span class="variable">${VERSION}</span>.tar.gz"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 移動檔案到正確的位置</span></span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span>/usr/bin</span><br><span class="line"><span class="built_in">mkdir</span> -p <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span>/usr/lib <span class="comment"># for .so files</span></span><br><span class="line"><span class="built_in">mv</span> <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span>/<span class="string">"WasmEdge-<span class="variable">${VERSION}</span>-Linux"</span>/bin/wasmedge <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span>/usr/bin/</span><br><span class="line"><span class="built_in">mv</span> <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span>/<span class="string">"WasmEdge-<span class="variable">${VERSION}</span>-Linux"</span>/lib/* <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span>/usr/lib/</span><br><span class="line"><span class="built_in">rm</span> -r <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span>/<span class="string">"WasmEdge-<span class="variable">${VERSION}</span>-Linux"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 執行 bake.sh 來建立 sysext</span></span><br><span class="line"><span class="string">"<span class="variable">${SCRIPTFOLDER}</span>"</span>/bake.sh <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 清理暫存檔</span></span><br><span class="line"><span class="built_in">rm</span> -rf <span class="string">"<span class="variable">${SYSEXTNAME}</span>"</span></span><br></pre></td></tr></table></figure><h3 id="執行腳本"><a href="#執行腳本" class="headerlink" title="執行腳本"></a>執行腳本</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">./create_wasmedge_sysext.sh 0.14.1 wasmedge</span><br><span class="line"></span><br><span class="line"><span class="comment"># Output</span></span><br><span class="line">WasmEdge-0.14.1-Linux/lib/</span><br><span class="line">WasmEdge-0.14.1-Linux/lib/libwasmedge.so.0</span><br><span class="line">WasmEdge-0.14.1-Linux/lib/libwasmedge.so.0.1.0</span><br><span class="line">WasmEdge-0.14.1-Linux/lib/libwasmedge.so</span><br><span class="line">WasmEdge-0.14.1-Linux/bin/</span><br><span class="line">WasmEdge-0.14.1-Linux/bin/wasmedge</span><br><span class="line">WasmEdge-0.14.1-Linux/bin/wasmedgec</span><br><span class="line">WasmEdge-0.14.1-Linux/include/</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/version.h</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/enum_types.h</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/enum.inc</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/enum_errcode.h</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/wasmedge.h</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/enum_configure.h</span><br><span class="line">WasmEdge-0.14.1-Linux/include/wasmedge/int128.h</span><br><span class="line">Parallel mksquashfs: Using 8 processors</span><br><span class="line">Creating 4.0 filesystem on wasmedge.raw, block size 131072.</span><br><span class="line">[==================================================\] 654/654 100%</span><br><span class="line"></span><br><span class="line">Exportable Squashfs 4.0 filesystem, gzip compressed, data block size 131072</span><br><span class="line">compressed data, compressed metadata, compressed fragments,</span><br><span class="line">compressed xattrs, compressed ids</span><br><span class="line">duplicates are removed</span><br><span class="line">Filesystem size 25975.38 Kbytes (25.37 Mbytes)</span><br><span class="line">31.16% of uncompressed filesystem size (83364.33 Kbytes)</span><br><span class="line">Inode table size 1930 bytes (1.88 Kbytes)</span><br><span class="line">65.42% of uncompressed inode table size (2950 bytes)</span><br><span class="line">Directory table size 140 bytes (0.14 Kbytes)</span><br><span class="line">56.91% of uncompressed directory table size (246 bytes)</span><br><span class="line">Number of duplicate files found 0</span><br><span class="line">Number of inodes 10</span><br><span class="line">Number of files 3</span><br><span class="line">Number of fragments 1</span><br><span class="line">Number of symbolic links 2</span><br><span class="line">Number of device nodes 0</span><br><span class="line">Number of fifo nodes 0</span><br><span class="line">Number of socket nodes 0</span><br><span class="line">Number of directories 5</span><br><span class="line">Number of ids (unique uids + gids) 1</span><br><span class="line">Number of uids 1</span><br><span class="line">root (0)</span><br><span class="line">Number of gids 1</span><br><span class="line">root (0)</span><br><span class="line">Created wasmedge.raw</span><br></pre></td></tr></table></figure><p>最後會產生一個 <code>wasmedge.raw</code> 的 sysext 檔案。請把它放到一個能被存取到的網路空間,我們後續在部署的時候會用到它。</p><hr><h2 id="在-DigitalOcean-上新增-Flatcar-Container-Linux-的客製化映像檔案"><a href="#在-DigitalOcean-上新增-Flatcar-Container-Linux-的客製化映像檔案" class="headerlink" title="在 DigitalOcean 上新增 Flatcar Container Linux 的客製化映像檔案"></a>在 DigitalOcean 上新增 Flatcar Container Linux 的客製化映像檔案</h2><p>由於 DigitalOcean 並沒有提供 Flatcar Container Linux 的映像檔案,因此我們需要自己建立一個客製化的映像檔案。<br>這邊的流程是參考 <a href="https://www.flatcar.org/docs/latest/installing/cloud/digitalocean/">Flatcar 的官方文件</a>。</p><h3 id="下載你想部署的對應版本映像檔"><a href="#下載你想部署的對應版本映像檔" class="headerlink" title="下載你想部署的對應版本映像檔"></a>下載你想部署的對應版本映像檔</h3><p>Flatcar 官方的映像檔路徑為 <code> https://<channel>.release.flatcar-linux.net/<arch>-usr/<version>/flatcar_production_digitalocean_image.bin.bz2</code>,其中:</p><ul><li><code><arch> 為 </code>amd64<code>或</code>arm64`</li><li><code><channel></code> 為 <code>stable</code>、<code>beta</code>、<code>alpha</code> 或 <code>lts</code></li><li><code><version></code> 為你想要部署的版本號。</li></ul><p>舉例而言,如果你想要部署 <code>4081.2.0</code> 版本、架構為 <code>amd64</code> 、且屬於穩定頻道的映像檔,你可以透過以下指令下載:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://stable.release.flatcar-linux.net/amd64-usr/4081.2.0/flatcar_production_digitalocean_image.bin.bz2</span><br></pre></td></tr></table></figure><h3 id="上傳映像檔到-DigitalOcean"><a href="#上傳映像檔到-DigitalOcean" class="headerlink" title="上傳映像檔到 DigitalOcean"></a>上傳映像檔到 DigitalOcean</h3><p>雖然官方說可以透過命令行來上傳映像檔,但我嘗試後發現他會一直卡住,不如透過網頁上傳穩定。</p><h4 id="進入-Backups-Snapshots-頁面"><a href="#進入-Backups-Snapshots-頁面" class="headerlink" title="進入 Backups & Snapshots 頁面"></a>進入 Backups & Snapshots 頁面</h4><p>客製化映像檔的管理頁面被藏在 Backups & Snapshots 頁面裏,點選 Custom Images 的分頁。</p><img src="/2024/12/12/deploy-flatcar-on-do/do-0-custom-image.png" class=""><h4 id="上傳映像檔"><a href="#上傳映像檔" class="headerlink" title="上傳映像檔"></a>上傳映像檔</h4><p>點擊 Upload Image 按鈕,選擇你下載的映像檔後,會跳出以下的表單,請填寫相關的訊息。</p><img src="/2024/12/12/deploy-flatcar-on-do/do-1-upload-image-box.png" class=""><h4 id="上傳中"><a href="#上傳中" class="headerlink" title="上傳中"></a>上傳中</h4><p>上傳中,請耐心等待。</p><img src="/2024/12/12/deploy-flatcar-on-do/do-2-uploading-image.png" class=""><h4 id="上傳完成後,會進入等待中"><a href="#上傳完成後,會進入等待中" class="headerlink" title="上傳完成後,會進入等待中"></a>上傳完成後,會進入等待中</h4><img src="/2024/12/12/deploy-flatcar-on-do/do-3-image-pending.png" class=""><h4 id="等處理完成,會出現以下畫面"><a href="#等處理完成,會出現以下畫面" class="headerlink" title="等處理完成,會出現以下畫面"></a>等處理完成,會出現以下畫面</h4><p>至少有個區域可用,就能夠繼續後面的步驟囉。</p><img src="/2024/12/12/deploy-flatcar-on-do/do-4-image-ready.png" class=""><hr><h2 id="在-DigitalOcean-上部署-Flatcar-Container-Linux"><a href="#在-DigitalOcean-上部署-Flatcar-Container-Linux" class="headerlink" title="在 DigitalOcean 上部署 Flatcar Container Linux"></a>在 DigitalOcean 上部署 Flatcar Container Linux</h2><p>由於在網頁上的使用介面不直覺,後續步驟我們會透過 DigitalOcean 的 API 在命令行中來進行操作。</p><h3 id="前置動作"><a href="#前置動作" class="headerlink" title="前置動作"></a>前置動作</h3><p>在部署之前,有些環境變數需要先設定與取得。</p><h4 id="取得-Personal-Access-Token"><a href="#取得-Personal-Access-Token" class="headerlink" title="取得 Personal Access Token"></a>取得 Personal Access Token</h4><p>到 <a href="https://cloud.digitalocean.com/account/api/tokens">Personal Access Token</a> 頁面</p><img src="/2024/12/12/deploy-flatcar-on-do/do-5-pat-page.png" class=""><p>點選 Generate New Token 按鈕</p><img src="/2024/12/12/deploy-flatcar-on-do/do-6-pat.png" class=""><p>這邊請選擇要給該 Token 什麼權限,這邊恕我偷懶選了 Full Access,本文用完就撤銷了。</p><h4 id="將-Personal-Access-Token-設定到環境變數"><a href="#將-Personal-Access-Token-設定到環境變數" class="headerlink" title="將 Personal Access Token 設定到環境變數"></a>將 Personal Access Token 設定到環境變數</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">read</span> TOKEN</span><br></pre></td></tr></table></figure><h4 id="設定-SSH-Key-ID"><a href="#設定-SSH-Key-ID" class="headerlink" title="設定 SSH Key ID"></a>設定 SSH Key ID</h4><p>請先使用網站上傳你的 SSH Key 或者使用 API 上傳 SSH Key,這個官方文件很詳細,請讓我跳過上傳的部分。</p><p>接著你需要取得已經上傳後的 SSH Key ID,這邊我們透過 API 來取得。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl --request GET <span class="string">"https://api.digitalocean.com/v2/account/keys"</span> \</span><br><span class="line"> --header <span class="string">"Authorization: Bearer <span class="variable">$TOKEN</span>"</span></span><br></pre></td></tr></table></figure><h5 id="SSH-Key-ID-在這邊"><a href="#SSH-Key-ID-在這邊" class="headerlink" title="SSH Key ID 在這邊"></a>SSH Key ID 在這邊</h5><p>上面指令執行以後,會得到以下的輸出,<code>id</code> 的那組數字就是我們後續會用到的 SSH Key ID。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"ssh_keys"</span><span class="punctuation">:</span><span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"id"</span><span class="punctuation">:</span><span class="number">12345678</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"public_key"</span><span class="punctuation">:</span><span class="string">"ssh-ed25519 ..."</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span><span class="string">"..."</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"fingerprint"</span><span class="punctuation">:</span><span class="string">"..."</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"links"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"pages"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"meta"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"total"</span><span class="punctuation">:</span><span class="number">1</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure><h4 id="將-SSH-Key-ID-設定到環境變數"><a href="#將-SSH-Key-ID-設定到環境變數" class="headerlink" title="將 SSH Key ID 設定到環境變數"></a>將 SSH Key ID 設定到環境變數</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">read</span> SSH_KEY_ID</span><br></pre></td></tr></table></figure><h4 id="取得映像檔-ID"><a href="#取得映像檔-ID" class="headerlink" title="取得映像檔 ID"></a>取得映像檔 ID</h4><p>在剛才上傳映像檔的時候,如果你有輸入 tag 的話,可以透過以下指令來取得映像檔 ID。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl --request GET <span class="string">"https://api.digitalocean.com/v2/images?type=distribution&private=true&tag_name=flatcar"</span> \</span><br><span class="line"> --header <span class="string">"Authorization: Bearer <span class="variable">$TOKEN</span>"</span></span><br></pre></td></tr></table></figure><h5 id="映像檔-ID-在這邊"><a href="#映像檔-ID-在這邊" class="headerlink" title="映像檔 ID 在這邊"></a>映像檔 ID 在這邊</h5><p>裏頭的 <code>id</code> 就是我們需要的資訊。</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"images"</span><span class="punctuation">:</span><span class="punctuation">[</span></span><br><span class="line"> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"id"</span><span class="punctuation">:</span><span class="number">123456789</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"name"</span><span class="punctuation">:</span><span class="string">"flatcar_production_digitalocean_image.bin.bz2"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"distribution"</span><span class="punctuation">:</span><span class="string">"Unknown OS"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"slug"</span><span class="punctuation">:</span><span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"public"</span><span class="punctuation">:</span><span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"regions"</span><span class="punctuation">:</span><span class="punctuation">[</span></span><br><span class="line"> <span class="string">"nyc2"</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"created_at"</span><span class="punctuation">:</span><span class="string">"2024-11-26T03:52:48Z"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"min_disk_size"</span><span class="punctuation">:</span><span class="number">7</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"type"</span><span class="punctuation">:</span><span class="string">"custom"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"size_gigabytes"</span><span class="punctuation">:</span><span class="number">0.66</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"description"</span><span class="punctuation">:</span><span class="string">""</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"tags"</span><span class="punctuation">:</span><span class="punctuation">[</span></span><br><span class="line"> <span class="string">"flatcar"</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"status"</span><span class="punctuation">:</span><span class="string">"available"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"error_message"</span><span class="punctuation">:</span><span class="string">""</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"links"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"pages"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"> <span class="punctuation">}</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"meta"</span><span class="punctuation">:</span><span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"total"</span><span class="punctuation">:</span><span class="number">1</span></span><br><span class="line"> <span class="punctuation">}</span></span><br><span class="line"><span class="punctuation">}</span></span><br></pre></td></tr></table></figure><h4 id="將映像檔-ID-設定到環境變數"><a href="#將映像檔-ID-設定到環境變數" class="headerlink" title="將映像檔 ID 設定到環境變數"></a>將映像檔 ID 設定到環境變數</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">read</span> IMAGE_ID</span><br></pre></td></tr></table></figure><hr><h3 id="建立-Droplet"><a href="#建立-Droplet" class="headerlink" title="建立 Droplet"></a>建立 Droplet</h3><h4 id="準備設定檔案"><a href="#準備設定檔案" class="headerlink" title="準備設定檔案"></a>準備設定檔案</h4><p>請注意,Flatcar Linux 是不可修改的,因此需要在部署之初就透過 Ignition 來進行初始化設定。</p><h5 id="WasmEdge-的範例"><a href="#WasmEdge-的範例" class="headerlink" title="WasmEdge 的範例"></a>WasmEdge 的範例</h5><h6 id="Ignition-的設定檔案"><a href="#Ignition-的設定檔案" class="headerlink" title="Ignition 的設定檔案"></a>Ignition 的設定檔案</h6><p>本質上就是把 wasmedge.raw 放入 <code>/opt/extensions/</code> 下,並且建立一個連結到 <code>/etc/extensions/wasmedge.raw</code>。</p><p>請將以下設定檔存入 <code>wasmedge.yaml</code> 中。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">variant:</span> <span class="string">flatcar</span></span><br><span class="line"><span class="attr">version:</span> <span class="number">1.0</span><span class="number">.0</span></span><br><span class="line"><span class="attr">storage:</span></span><br><span class="line"> <span class="attr">files:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">path:</span> <span class="string">/opt/extensions/wasmedge-0.14.1-x86-64.raw</span></span><br><span class="line"> <span class="attr">mode:</span> <span class="number">0420</span></span><br><span class="line"> <span class="attr">contents:</span></span><br><span class="line"> <span class="attr">source:</span> <span class="string">https://github.com/second-state/flatcar-sysext-bakery/releases/download/0.0.1/wasmedge-0.14.1-x86-64.raw</span></span><br><span class="line"> <span class="attr">links:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">target:</span> <span class="string">/opt/extensions/wasmedge-0.14.1-x86-64.raw</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">/etc/extensions/wasmedge.raw</span></span><br><span class="line"> <span class="attr">hard:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure><h6 id="轉換成-JSON-格式"><a href="#轉換成-JSON-格式" class="headerlink" title="轉換成 JSON 格式"></a>轉換成 JSON 格式</h6><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> wasmedge.yaml | docker run --<span class="built_in">rm</span> -i quay.io/coreos/butane:latest > wasmedge.json</span><br></pre></td></tr></table></figure><h4 id="部署-Droplet"><a href="#部署-Droplet" class="headerlink" title="部署 Droplet"></a>部署 Droplet</h4><p>我選了相對便宜的機器 <code>s-1vcpu-1gb</code>,你可以根據需求選擇適合的機器。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">curl --request POST <span class="string">"https://api.digitalocean.com/v2/droplets"</span> \</span><br><span class="line"> --header <span class="string">"Content-Type: application/json"</span> \</span><br><span class="line"> --header <span class="string">"Authorization: Bearer <span class="variable">$TOKEN</span>"</span> \</span><br><span class="line"> --data <span class="string">'{</span></span><br><span class="line"><span class="string"> "region":"nyc3",</span></span><br><span class="line"><span class="string"> "image":"'</span><span class="variable">$IMAGE_ID</span><span class="string">'",</span></span><br><span class="line"><span class="string"> "size":"s-1vcpu-1gb",</span></span><br><span class="line"><span class="string"> "name":"core-5",</span></span><br><span class="line"><span class="string"> "private_networking":true,</span></span><br><span class="line"><span class="string"> "ssh_keys":['</span><span class="variable">$SSH_KEY_ID</span><span class="string">'],</span></span><br><span class="line"><span class="string"> "user_data": "'</span><span class="string">"<span class="subst">$(cat wasmedge.json | sed 's/<span class="string">"/\\"</span>/g')</span>"</span><span class="string">'"</span></span><br><span class="line"><span class="string">}'</span></span><br></pre></td></tr></table></figure><h5 id="登入-Droplet"><a href="#登入-Droplet" class="headerlink" title="登入 Droplet"></a>登入 Droplet</h5><p>來到 Droplet 的頁面就能看到一台已經部署好的 Droplet 正在努力工作中。</p><img src="/2024/12/12/deploy-flatcar-on-do/do-droplet-0.png" class=""><p>使用 SSH 連線到 Droplet。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ssh core@<Droplet IP></span><br><span class="line"><span class="comment"># 在本範例中 ssh [email protected]</span></span><br></pre></td></tr></table></figure><h6 id="檢查是否有安裝成功"><a href="#檢查是否有安裝成功" class="headerlink" title="檢查是否有安裝成功"></a>檢查是否有安裝成功</h6><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Flatcar Container Linux by Kinvolk stable 4081.2.0 <span class="keyword">for</span> DigitalOcean</span><br><span class="line">core@core-5 ~ $ wasmedge --version</span><br><span class="line">wasmedge version 0.14.1</span><br><span class="line"> (plugin <span class="string">"wasi_logging"</span>) version 0.1.0.0</span><br></pre></td></tr></table></figure><h6 id="執行-Wasm-應用程式"><a href="#執行-Wasm-應用程式" class="headerlink" title="執行 Wasm 應用程式"></a>執行 Wasm 應用程式</h6><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">wget https://github.com/second-state/flatcar-sysext-bakery/releases/download/0.0.3/hello_world.wasm</span><br><span class="line">wasmedge hello_world.wasm</span><br></pre></td></tr></table></figure><p>預期的輸出:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Greeting from WasmEdge (=゚ω゚)ノ</span><br></pre></td></tr></table></figure><p>到此就完成部署囉!</p><hr><h5 id="LlamaEdge-的範例"><a href="#LlamaEdge-的範例" class="headerlink" title="LlamaEdge 的範例"></a>LlamaEdge 的範例</h5><h6 id="Ignition-的設定檔案-1"><a href="#Ignition-的設定檔案-1" class="headerlink" title="Ignition 的設定檔案"></a>Ignition 的設定檔案</h6><p>LlamaEdge 是執行在 WasmEdge 之上的,因此需要跟前一個範例一樣,先設定 WasmEdge</p><p>把 wasmedge.raw 放入 <code>/opt/extensions/</code> 下,並且建立一個連結到 <code>/etc/extensions/wasmedge.raw</code>。<br>接著再把 llamaedge.raw 放入 <code>/opt/extensions/</code> 下,並且建立一個連結到 <code>/etc/extensions/llamaedge.raw</code>。</p><p>請將以下設定檔存入 <code>llamaedge.yaml</code> 中。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">variant:</span> <span class="string">flatcar</span></span><br><span class="line"><span class="attr">version:</span> <span class="number">1.0</span><span class="number">.0</span></span><br><span class="line"><span class="attr">storage:</span></span><br><span class="line"> <span class="attr">files:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">path:</span> <span class="string">/opt/extensions/wasmedge-0.14.1-x86-64.raw</span></span><br><span class="line"> <span class="attr">mode:</span> <span class="number">0420</span></span><br><span class="line"> <span class="attr">contents:</span></span><br><span class="line"> <span class="attr">source:</span> <span class="string">https://github.com/second-state/flatcar-sysext-bakery/releases/download/0.0.3/wasmedge-0.14.1-x86-64.raw</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">path:</span> <span class="string">/opt/extensions/llamaedge-0.14.16-x86-64.raw</span></span><br><span class="line"> <span class="attr">mode:</span> <span class="number">0420</span></span><br><span class="line"> <span class="attr">contents:</span></span><br><span class="line"> <span class="attr">source:</span> <span class="string">https://github.com/second-state/flatcar-sysext-bakery/releases/download/0.0.3/llamaedge-0.14.16-x86-64.raw</span></span><br><span class="line"> <span class="attr">links:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">target:</span> <span class="string">/opt/extensions/llamaedge-0.14.16-x86-64.raw</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">/etc/extensions/llamaedge.raw</span></span><br><span class="line"> <span class="attr">hard:</span> <span class="literal">false</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">target:</span> <span class="string">/opt/extensions/wasmedge-0.14.1-x86-64.raw</span></span><br><span class="line"> <span class="attr">path:</span> <span class="string">/etc/extensions/wasmedge.raw</span></span><br><span class="line"> <span class="attr">hard:</span> <span class="literal">false</span></span><br></pre></td></tr></table></figure><h6 id="轉換成-JSON-格式-1"><a href="#轉換成-JSON-格式-1" class="headerlink" title="轉換成 JSON 格式"></a>轉換成 JSON 格式</h6><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> llamaedge.yaml | docker run --<span class="built_in">rm</span> -i quay.io/coreos/butane:latest > llamaedge.json</span><br></pre></td></tr></table></figure><h4 id="部署-Droplet-1"><a href="#部署-Droplet-1" class="headerlink" title="部署 Droplet"></a>部署 Droplet</h4><p>我選了相對便宜的機器 <code>s-1vcpu-1gb</code>,你可以根據需求選擇適合的機器。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">curl --request POST <span class="string">"https://api.digitalocean.com/v2/droplets"</span> \</span><br><span class="line"> --header <span class="string">"Content-Type: application/json"</span> \</span><br><span class="line"> --header <span class="string">"Authorization: Bearer <span class="variable">$TOKEN</span>"</span> \</span><br><span class="line"> --data <span class="string">'{</span></span><br><span class="line"><span class="string"> "region":"nyc3",</span></span><br><span class="line"><span class="string"> "image":"'</span><span class="variable">$IMAGE_ID</span><span class="string">'",</span></span><br><span class="line"><span class="string"> "size":"s-1vcpu-1gb",</span></span><br><span class="line"><span class="string"> "name":"core-5",</span></span><br><span class="line"><span class="string"> "private_networking":true,</span></span><br><span class="line"><span class="string"> "ssh_keys":['</span><span class="variable">$SSH_KEY_ID</span><span class="string">'],</span></span><br><span class="line"><span class="string"> "user_data": "'</span><span class="string">"<span class="subst">$(cat llamaedge.json | sed 's/<span class="string">"/\\"</span>/g')</span>"</span><span class="string">'"</span></span><br><span class="line"><span class="string">}'</span></span><br></pre></td></tr></table></figure><h5 id="登入-Droplet-1"><a href="#登入-Droplet-1" class="headerlink" title="登入 Droplet"></a>登入 Droplet</h5><p>使用 SSH 連線到 Droplet。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ssh core@<Droplet IP></span><br><span class="line"><span class="comment"># 在本範例中 ssh [email protected]</span></span><br></pre></td></tr></table></figure><h6 id="下載模型"><a href="#下載模型" class="headerlink" title="下載模型"></a>下載模型</h6><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://huggingface.co/second-state/Llama-3.2-1B-Instruct-GGUF/resolve/main/Llama-3.2-1B-Instruct-Q2_K.gguf</span><br></pre></td></tr></table></figure><h6 id="啟動-LlamaEdge-API-Server"><a href="#啟動-LlamaEdge-API-Server" class="headerlink" title="啟動 LlamaEdge API Server"></a>啟動 LlamaEdge API Server</h6><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">MODEL_FILE=<span class="string">"Llama-3.2-1B-Instruct-Q2_K.gguf"</span></span><br><span class="line">API_SERVER_WASM=<span class="string">"/usr/lib/wasmedge/wasm/llama-api-server.wasm"</span></span><br><span class="line">PROMPT_TEMPLATE=<span class="string">"llama-3-chat"</span></span><br><span class="line">CONTEXT_SIZE=128</span><br><span class="line">MODEL_NAME=<span class="string">"llama-3.2-1B"</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">nohup</span> wasmedge \</span><br><span class="line"> --<span class="built_in">dir</span> .:. \</span><br><span class="line"> --nn-preload default:GGML:AUTO:<span class="variable">${MODEL_FILE}</span> \</span><br><span class="line"> <span class="variable">${API_SERVER_WASM}</span> \</span><br><span class="line"> --prompt-template <span class="variable">${PROMPT_TEMPLATE}</span> \</span><br><span class="line"> --ctx-size <span class="variable">${CONTEXT_SIZE}</span> \</span><br><span class="line"> --model-name <span class="variable">${MODEL_NAME}</span> &</span><br></pre></td></tr></table></figure><h6 id="送-Request-給-LlamaEdge-API-Server"><a href="#送-Request-給-LlamaEdge-API-Server" class="headerlink" title="送 Request 給 LlamaEdge API Server"></a>送 Request 給 LlamaEdge API Server</h6><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">curl -X POST http://localhost:8080/v1/chat/completions \</span><br><span class="line"> -H <span class="string">'accept:application/json'</span> \</span><br><span class="line"> -H <span class="string">'Content-Type: application/json'</span> \</span><br><span class="line"> -d <span class="string">'{"messages":[{"role":"system", "content": "You are a helpful assistant. Reply in short sentence"}, {"role":"user", "content": "What is the capital of Japan?"}], "model":"llama-3.2-1B"}'</span></span><br></pre></td></tr></table></figure><p>預期的輸出:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="string">"id"</span>:<span class="string">"chatcmpl-4a5a6487-3a47-4a79-86aa-0dd381dd71f7"</span>,</span><br><span class="line"> <span class="string">"object"</span>:<span class="string">"chat.completion"</span>,</span><br><span class="line"> <span class="string">"created"</span>:1734020512,</span><br><span class="line"> <span class="string">"model"</span>:<span class="string">"llama-3.2-1B"</span>,</span><br><span class="line"> <span class="string">"choices"</span>:[</span><br><span class="line"> {</span><br><span class="line"> <span class="string">"index"</span>:0,</span><br><span class="line"> <span class="string">"message"</span>:{</span><br><span class="line"> <span class="string">"content"</span>:<span class="string">"The capital of Japan is Tokyo."</span>,</span><br><span class="line"> <span class="string">"role"</span>:<span class="string">"assistant"</span></span><br><span class="line"> },</span><br><span class="line"> <span class="string">"finish_reason"</span>:<span class="string">"stop"</span>,</span><br><span class="line"> <span class="string">"logprobs"</span>:null</span><br><span class="line"> }</span><br><span class="line"> ],</span><br><span class="line"> <span class="string">"usage"</span>:{</span><br><span class="line"> <span class="string">"prompt_tokens"</span>:32,</span><br><span class="line"> <span class="string">"completion_tokens"</span>:9,</span><br><span class="line"> <span class="string">"total_tokens"</span>:41</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>若對 LlamaEdge 有更多興趣,請直接到該專案的 GitHub 頁面查看更多資訊。</p><p>謝謝大家的收看 :-)</p><h2 id="寫在最後"><a href="#寫在最後" class="headerlink" title="寫在最後"></a>寫在最後</h2><p>謝謝朋友的關心,關於在 DigitalOcean 上發生的事情就是我想測試能不能也啟動 GPU 的 Droplet 來進行更有效能的 LLM 測試,可惜 DigitalOcean 拒絕了我。<br>我根據官方頁面申請了 GPU Droplet 的限額,然後下面是他們的回信,因此在上面的工作都完成後,我已經移除所有在 DO 上面的 Droplet 與客製化映像檔。<br>將來也不打算在上面部署其他的服務,因為很明顯地,DigitalOcean 不願服務我這種小客戶。Azure、GCP、AWS 都相對友善,就算是奈米客戶,也能獲得相關的資源。<br>在此,我個人強烈建議可以使用其他的雲端服務廠商,而不是 DigitalOcean。</p><p>以下為收到的原文,為避免該工作人員困擾,我將使用 XXX 取代人名:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">Hello,</span><br><span class="line"></span><br><span class="line">Greetings from DigitalOcean!</span><br><span class="line"></span><br><span class="line">Thanks for reaching out, my name is XXX from DigitalOcean Support.</span><br><span class="line"></span><br><span class="line">After reviewing your account and your request, we are unable to approve access</span><br><span class="line"> to GPU Droplets at this time for your team.</span><br><span class="line"></span><br><span class="line">We would be happy to consider your request for a higher resource limit after</span><br><span class="line"> you have additional billing history on our platform.</span><br><span class="line">To provide additional context to what that means, invoices generate on the</span><br><span class="line"> first day of every month and are based on the services consumed in the prior</span><br><span class="line"> billing cycle. As invoices are generated and successfully paid using the</span><br><span class="line"> payment method on file for your team, this generates billing history which</span><br><span class="line"> is what we use to determine eligibility for resource limit increases.</span><br><span class="line"></span><br><span class="line">Should you have any questions or require further assistance regarding this</span><br><span class="line"> request, please do not hesitate to reach out to us.</span><br><span class="line"></span><br><span class="line">Warm Regards,</span><br><span class="line"></span><br><span class="line">XXX</span><br><span class="line">Associate Customer Advocate</span><br><span class="line">DigitalOcean Support</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>之前在 Flatcar 的系統擴充元件提了<a href="https://github.com/flatcar/sysext-bakery/pulls?q=is:pr+author:hydai+is:closed">兩個 PRs</a>,讓 <a href="https://github.com/WasmEdge/WasmEdge/">WasmEdge</a> 與 <a href="https://github.com/LlamaEdge/LlamaEdge">LlamaEdge</a> 能以 sysext 的方式在 Flatcar 被部署時,一起被安裝在裡頭。因為跟 DigitalOcean 發生了一些事,因此決定留下筆記以後,準備遷移到 Azure 或其他友善的平台。</p>
<p>本文將涵蓋:</p>
<ol>
<li>如何建立屬於你的 Flatcar Sysext(系統擴充元件)。</li>
<li>如何在 DigitalOcean 上新增 Flatcar Container Linux 的客製化映像檔案。</li>
<li>如何在 DigitalOcean 上部署 Flatcar Container Linux。</li>
<li>如何執行 Wasm 的應用程式(利益揭露,我是 WasmEdge 的維護者)。</li>
<li>如何部署大語言模型(LLM)在 Flatcar Container Linux 上,使用 LlamaEdge 為例。(利益揭露,這個專案會編譯成 Wasm 格式,並執行在 WasmEdge 之上)。</li>
</ol></summary>
<category term="Note" scheme="https://hyd.ai/categories/Note/"/>
<category term="Flatcar" scheme="https://hyd.ai/tags/Flatcar/"/>
<category term="Linux" scheme="https://hyd.ai/tags/Linux/"/>
<category term="DigitalOcean" scheme="https://hyd.ai/tags/DigitalOcean/"/>
<category term="LLM" scheme="https://hyd.ai/tags/LLM/"/>
<category term="WasmEdge" scheme="https://hyd.ai/tags/WasmEdge/"/>
<category term="WebAssembly" scheme="https://hyd.ai/tags/WebAssembly/"/>
<category term="Wasm" scheme="https://hyd.ai/tags/Wasm/"/>
<category term="WASI-NN" scheme="https://hyd.ai/tags/WASI-NN/"/>
</entry>
<entry>
<title>遊戲用設備紀錄@2024</title>
<link href="https://hyd.ai/2024/12/08/game-console-2024/"/>
<id>https://hyd.ai/2024/12/08/game-console-2024/</id>
<published>2024-12-08T10:38:19.000Z</published>
<updated>2024-12-08T11:35:02.041Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>這篇文章主力紀錄目前正在服役中的遊戲用設備,算是幫 2024 年的自己做個總結。<br>預計每年年末都會更新一次,以便未來回顧。</p><span id="more"></span><h2 id="全部設備"><a href="#全部設備" class="headerlink" title="全部設備"></a>全部設備</h2><ul><li>桌機<ul><li>CPU: AMD Ryzen 9 5900X (2020/11/5 首發排隊購入,AMD Yes!)</li><li>主機板: ASUS ROG Crosshair VIII Hero (WI-FI) (跟 5900X 一起買)</li><li>顯示卡: ASUS ROG STRIX RTX3080TI O12G GAMING (2022 年購入打遊戲)</li><li>記憶體: G.SKILL 焰光戟 32GBx2 DDR4-4000 (2022 年升級)</li><li>SSD1: Samsung 970 Pro 1TB (2020 年購入)</li><li>SSD2: Samsung 990 Pro 4TB (2024 年黑五史上新低價購入)</li><li>電源供應器: ASUS ROG 750W 金牌 全模 十年保 (買 3080TI 時送的)</li><li>機殼: ASUS TUF Gaming GT301 ATX (買 5900X 送的)</li><li>顯示器: Sony KD-55X9500G (2019 年購入)</li><li>鍵盤: Majestouch Convertible 3 Tenkeyless 黑軸</li><li>滑鼠: Logitech G502</li><li>耳機: Sony INZONE H9 / ATH-A900X</li><li>麥克風: Blue Yeti X</li><li>椅子: Herman Miller Aeron 全功能 (2015 年購入)</li></ul></li><li>家用主機<ul><li>Sony PS4 Pro (丟老家當 remote 連線主機)</li><li>Sony PS5</li><li>Nintendo Switch 初代</li><li>Nintendo Switch Lite</li><li>Nintendo Switch 動森版</li></ul></li><li>掌上型遊戲機<ul><li>Sony PS Vita</li><li>New Nintendo 3DS XL * 2</li><li>Apple iPhone 11 Pro</li><li>Apple iPhone 13 Pro</li><li>Apple iPhone 15 Pro (當前主力機)</li><li>Apple iPad Pro M1 11” (他寫第三代,但這個命名我已經不知道是哪一代了XD)</li><li>Sony PlayStation Portal</li><li>Steam Deck OLED</li></ul></li></ul><h2 id="設備用途"><a href="#設備用途" class="headerlink" title="設備用途"></a>設備用途</h2><p>上次跟朋友聊到我目前的遊戲用設備配置,被問到最多的就是上面那麼多設備到底在玩什麼遊戲,哪來那麼多時間玩遊戲。<br>其實很多時候我也不知道,很多時候我是因為「想要玩」所以就買了,有沒有「真的玩」就是另一回事了。<br>就如同 Steam 的遊戲庫,裡面有太多買的遊戲,但要說真的有玩多少,可能不到一成有完全破關。<br>有時候覺得很疲倦,我都花了錢買了遊戲,還要花時間玩遊戲,想想就累了。或許這就是電子陽痿吧。</p><p>以下把上面這些服役中的設備的用途都整理一下,或許能知道這些的價值在哪裡。</p><h3 id="突然想回味當年"><a href="#突然想回味當年" class="headerlink" title="突然想回味當年"></a>突然想回味當年</h3><p>有些遊戲並沒有移植到新平台上,想遊玩只能使用舊的機器。</p><ul><li>Sony PS Vita</li><li>New Nintendo 3DS XL * 2</li></ul><p>以上的兩款機器平時幾乎不會開,PSV 大概一年會玩一兩次,3DS 則是想到以前的寶可夢戰友們就會打開來回味。</p><h3 id="放置型遊戲"><a href="#放置型遊戲" class="headerlink" title="放置型遊戲"></a>放置型遊戲</h3><p>這類遊戲通常就是擺著讓他跑,看著就很療癒的手機遊戲。<br>退役的手機效能夠用,平常就放在桌上看都很愉快。</p><ul><li>Apple iPhone 11 Pro</li><li>Apple iPhone 13 Pro</li></ul><h3 id="出門在外-回老家"><a href="#出門在外-回老家" class="headerlink" title="出門在外 / 回老家"></a>出門在外 / 回老家</h3><p>以方便攜帶為主,每次長途通勤時會想帶著來消磨時間。</p><ul><li>Apple iPad Pro M1 11” (買前生產力,買後打遊戲)</li><li>Steam Deck OLED (各種獨立遊戲)</li><li>Nintendo Switch 動森版 (初代&Lite 現在各自是特殊遊戲專用機)</li></ul><h3 id="認真在家打遊戲"><a href="#認真在家打遊戲" class="headerlink" title="認真在家打遊戲"></a>認真在家打遊戲</h3><h4 id="PS-家族"><a href="#PS-家族" class="headerlink" title="PS 家族"></a>PS 家族</h4><p>我以前對於家用主機很嚮往,但一直沒有興趣購買,畢竟最初並沒有遇見獨佔的遊戲。<br>直到某一天魔物獵人世界/冰原的到來,不買不行。<br>於是入手了 PS4 Pro,也幫她加裝了 SSD,不然那個讀取等待時間,時光可貴,別揮霍。</p><p>後來疫情時代,PS5 也發售了,然而我最初並沒有想買,只是看到他飢餓行銷,不抽白不抽,頂多抽中了讓給朋友。<br>結果我抽中了,朋友也抽中了,於是 PS5 就在我家住了下來。<br>可惜 PS5 的獨佔遊戲太少,號稱 8K 也是夢裡相見,我基本上當他是台藍光播放器用。<br>過了這麼久 PS5 Pro 都出來了,那這台 PS5 現在是什麼用途呢?PS VR2 + DMM VR :-) 懂得就懂。</p><p>意外之喜是今年的 PlayStation Portal,這台機器是我今年的泡澡專用機,可以一邊泡澡,一邊打 PS5 的遊戲,而且還具備 PS 手把原生的震動與自適應板機。<br>我的劍星、FF7 Remake、宇宙機器人都在這上面玩過,真的是太舒服了。</p><h4 id="桌機"><a href="#桌機" class="headerlink" title="桌機"></a>桌機</h4><p>實際上最認真玩的還是桌機,老黃的 3080Ti 天下無敵,模擬飛行、COD、FF14 等各種大作都可以跑得很順。<br>更何況現在越來越多遊戲也不再是獨佔遊戲了,我正在將重心從家用主機搬移到桌機上。</p><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p>算是幫自己記錄一下,也讓自己知道到底有多少遊戲用設備。2025 年如果還要添購新設備之前,需小心謹慎,別讓衝動變成後悔。</p><p>給 2025 年的自己,到時候你又買了什麼新設備呢?</p>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>這篇文章主力紀錄目前正在服役中的遊戲用設備,算是幫 2024 年的自己做個總結。<br>預計每年年末都會更新一次,以便未來回顧。</p></summary>
<category term="Note" scheme="https://hyd.ai/categories/Note/"/>
<category term="2024" scheme="https://hyd.ai/tags/2024/"/>
<category term="遊戲用設備" scheme="https://hyd.ai/tags/%E9%81%8A%E6%88%B2%E7%94%A8%E8%A8%AD%E5%82%99/"/>
</entry>
<entry>
<title>加速 macOS 的 Time Machine 備份速度</title>
<link href="https://hyd.ai/2024/11/24/time-machine-speed-up/"/>
<id>https://hyd.ai/2024/11/24/time-machine-speed-up/</id>
<published>2024-11-24T08:58:22.000Z</published>
<updated>2024-11-24T09:20:13.427Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>macOS 的 Time Machine 是一個非常好用的備份工具,它曾經多次救援我人生的重要時刻。當時碩士論文寫到一半,macbook pro 直接壞掉,幸好有 Time Machine 的備份,讓我可以如期畢業。</p><p>但是隨著使用的容量越來越大,在備份的過程中,有時候會發現備份的速度變成異常緩慢,甚至出現要十幾個小時才能完成一次備份,尤其人在國外時深感危險。</p><p>在搜尋的時候發現其實世界上有一大堆人也有相同的問題,幾乎都有標準做法了<code>(/ω\)</code></p><span id="more"></span><h2 id="解決方法"><a href="#解決方法" class="headerlink" title="解決方法"></a>解決方法</h2><p>與其他的備份方式不同,Time Machine 有個隱藏的參數會將備份的速度限制在一個較低的數值,且相關的優先順序也是在較低的位置,因此如果不改變這個數值的話,Time Machine 的備份速度就會隨著積累的增加而變得越來越慢。</p><p>很遺憾的是,這個數值是隱藏的,因此我們需要透過終端機來修改這個數值。</p><p>打開終端機以後,輸入以下指令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sysctl debug.lowpri_throttle_enabled=0</span><br></pre></td></tr></table></figure><p>這樣一來,Time Machine 的備份速度就會恢復到正常的速度了。</p><h3 id="指令解釋"><a href="#指令解釋" class="headerlink" title="指令解釋"></a>指令解釋</h3><p><code>sudo</code> 是因為我們需要透過 <code>sysctl</code> 進行系統參數的修改,而這個指令是需要 root 權限才能使用的。</p><p><code>sysctl</code> 是一個在 Unix-like 的作業系統中專門用來讀取與修改內核參數的工具。</p><p><code>debug.lowpri_throttle_enabled</code> 是一個參數,當這個參數為 1 時,Time Machine 的備份速度會被限制在一個較低的數值,當這個參數為 0 時,Time Machine 的備份速度就不再受到此限制。</p><p><code>lowpri</code> 是 low priority 的縮寫,<code>throttle</code> 是節流閥的意思,表示限制流量,<code>enabled</code> 是啟用的意思,因此這個參數的意思就是啟用低優先順序的限制。</p><h2 id="恢復原來的設定"><a href="#恢復原來的設定" class="headerlink" title="恢復原來的設定"></a>恢復原來的設定</h2><p>上面的修改會在重新開機後被重置,因此即使忘記恢復原本的設定也沒關係,時間會解決一切。</p><p>若完成備份之後,還是想要馬上恢復成原本的設定,可以輸入以下指令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sudo</span> sysctl debug.lowpri_throttle_enabled=1</span><br></pre></td></tr></table></figure><h2 id="方便的別名"><a href="#方便的別名" class="headerlink" title="方便的別名"></a>方便的別名</h2><p>每次都需要輸入這麼長的指令也是很麻煩的,因此可以使用 <code>alias</code> 來建立一個別名,這樣就能用短短的指令做到同樣的事囉。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 請在你的 .bashrc 或 .zshrc 中加入以下指令</span></span><br><span class="line"><span class="built_in">alias</span> tmspup=<span class="string">'sudo sysctl debug.lowpri_throttle_enabled=0'</span></span><br><span class="line"><span class="built_in">alias</span> tmspdown=<span class="string">'sudo sysctl debug.lowpri_throttle_enabled=1'</span></span><br><span class="line"><span class="comment"># 日後就能使用 tmspup 與 tmspdown 來快速的切換 Time Machine 的備份速度了</span></span><br></pre></td></tr></table></figure><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><ul><li><a href="https://www.howtogeek.com/843598/how-to-speed-up-your-time-machine-backups/">How to Speed Up Your Time Machine Backups</a></li></ul>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>macOS 的 Time Machine 是一個非常好用的備份工具,它曾經多次救援我人生的重要時刻。當時碩士論文寫到一半,macbook pro 直接壞掉,幸好有 Time Machine 的備份,讓我可以如期畢業。</p>
<p>但是隨著使用的容量越來越大,在備份的過程中,有時候會發現備份的速度變成異常緩慢,甚至出現要十幾個小時才能完成一次備份,尤其人在國外時深感危險。</p>
<p>在搜尋的時候發現其實世界上有一大堆人也有相同的問題,幾乎都有標準做法了<code>(/ω\)</code></p></summary>
<category term="Note" scheme="https://hyd.ai/categories/Note/"/>
<category term="macOS" scheme="https://hyd.ai/tags/macOS/"/>
<category term="Time Machine" scheme="https://hyd.ai/tags/Time-Machine/"/>
</entry>
<entry>
<title>蓋一個簡單的縮網址服務</title>
<link href="https://hyd.ai/2024/11/19/url-shortener/"/>
<id>https://hyd.ai/2024/11/19/url-shortener/</id>
<published>2024-11-19T05:06:22.000Z</published>
<updated>2024-11-19T05:51:22.934Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>之前的縮網址服務我是使用 picsee 來做的,但在免費的方案中,並不支援 HTTPS,這個影響很大,如果在 URL 中存在 HTTPS 的話,轉址服務就會失效。</p><p>P.S. 因為我很不滿意 picsee 就不放上連結了,此外,我也非常不建議大家使用。</p><p>雖然有段時間可以使用 Cloudflare 的 Proxy 來讓他有 HTTPS 的樣子,可是某次更新後也失效了,而且我發現失效的時候是在演講前,因此當了盤子付了一千台幣買了一年的進階網址服務。</p><p>早知道這麼麻煩,當初應該在不緊急的時候先搬遷到 <a href="https://lihi.io/">lihi</a> 上面,畢竟都要付錢了,當然要找一家好一點的服務商。</p><p>然而,過了一段時間,我發現我其實不需要這麼多功能,只是想要一個簡單的縮網址服務而已,我並不需要追蹤成效,也不需要網址的統計,因為我唯一需要的功能就只是讓我的聽眾可以用短一點的網址拿到投影片或者是其他的資料。<br>在這時意外看到了 <a href="https://github.com/sitcon-tw/URL-Shortener">SITCON 的 URL-Shortener</a>,我發現這個服務就是我想要的。</p><p>在功能上:</p><ul><li>可以自訂網址</li><li>可以加上該網址的簡介</li><li>可以放圖片</li><li>全部都是 markdown 語法</li><li>可以用 GitHub workflow 來自動部署</li></ul><p>因此我就以他的專案為基礎,自己做了一個<a href="https://github.com/hydai/URL-Shortener">相似的縮網址服務</a></p><span id="more"></span><p>以下來說明一下整個建立的流程,如果有其他夥伴想架設自己的服務,可以參考。</p><h2 id="建立縮網址服務"><a href="#建立縮網址服務" class="headerlink" title="建立縮網址服務"></a>建立縮網址服務</h2><p>在這個專案中,我使用 Jekyll 來建立重導向的機制,並且使用 GitHub Pages 來部署。</p><h3 id="安裝-Jekyll"><a href="#安裝-Jekyll" class="headerlink" title="安裝 Jekyll"></a>安裝 Jekyll</h3><p>我的環境在 macOS 上,由於不想與 macOS 內建的 Ruby 衝突,因此我使用 chruby 與 ruby-install 來管理與安裝 ruby。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">brew install chruby ruby-install</span><br><span class="line">ruby-install ruby 3.3.6 <span class="comment"># 裝了當前最新的版本</span></span><br></pre></td></tr></table></figure><p>接著需要在環境裡將路徑加入到 <code>~/.bashrc</code> 或者 <code>~/.zshrc</code> 中。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> PATH=<span class="string">"<span class="variable">$HOME</span>/.rubies/ruby-3.3.6/bin:<span class="variable">$PATH</span>"</span> <span class="comment"># 請將 3.3.6 換成你安裝的版本</span></span><br></pre></td></tr></table></figure><p>接著安裝 Jekyll</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gem install jekyll bundler</span><br></pre></td></tr></table></figure><h3 id="建立專案"><a href="#建立專案" class="headerlink" title="建立專案"></a>建立專案</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jekyll new url-shortener</span><br></pre></td></tr></table></figure><p>這時你的目錄應該有以下的檔案:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">├── 404.html</span><br><span class="line">├── Gemfile</span><br><span class="line">├── Gemfile.lock</span><br><span class="line">├── _config.yml</span><br><span class="line">├── _posts</span><br><span class="line">│ └── 2024-11-19-welcome-to-jekyll.markdown</span><br><span class="line">├── about.markdown</span><br><span class="line">└── index.markdown</span><br></pre></td></tr></table></figure><p>然而,作為一個短網址服務,實際上我們只需要重導向的機制,因此我們先把不需要的檔案刪掉。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> -rf _posts about.markdown</span><br></pre></td></tr></table></figure><p>刪除完以後會剩這些:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">├── 404.html</span><br><span class="line">├── Gemfile</span><br><span class="line">├── Gemfile.lock</span><br><span class="line">├── _config.yml</span><br><span class="line">└── index.markdown</span><br></pre></td></tr></table></figure><h3 id="建立重導向的版型與配置"><a href="#建立重導向的版型與配置" class="headerlink" title="建立重導向的版型與配置"></a>建立重導向的版型與配置</h3><p>此時,我們需要建立兩個資料夾,一個是 <code>_layouts</code> 用來放置版型,另一個是 <code>_redirects</code> 用來放置重導向的配置。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> _layouts _redirects</span><br></pre></td></tr></table></figure><h4 id="重導向的版型"><a href="#重導向的版型" class="headerlink" title="重導向的版型"></a>重導向的版型</h4><p>在 <code>_layouts</code> 裡面建立一個 <code>redirects.html</code> 的檔案,這個檔案是用來建立重導向的版型,這個版型可以隨意更改,是以 SITCON 的為範本,設定為 0.5 秒後轉到目標網址去。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE <span class="keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"zh-Hant-TW"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>{{ page.title }}<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"description"</span> <span class="attr">content</span>=<span class="string">"{{ page.description }}"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"author"</span> <span class="attr">content</span>=<span class="string">"hydai"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">property</span>=<span class="string">"og:title"</span> <span class="attr">content</span>=<span class="string">"{{ page.title }}"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">property</span>=<span class="string">"og:description"</span> <span class="attr">content</span>=<span class="string">"{{ page.description }}"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">property</span>=<span class="string">"og:image"</span> <span class="attr">content</span>=<span class="string">"{{ page.image }}"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">property</span>=<span class="string">"og:site_name"</span> <span class="attr">content</span>=<span class="string">"hydai"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">property</span>=<span class="string">"og:locale"</span> <span class="attr">content</span>=<span class="string">"zh_TW"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">script</span>></span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>) {</span></span><br><span class="line"><span class="language-javascript"> <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span> = <span class="string">"{{ page.redirect_to }}"</span>;</span></span><br><span class="line"><span class="language-javascript"> }, <span class="number">500</span>);</span></span><br><span class="line"><span class="language-javascript"> </span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>重新導向到 (redirect to) <span class="tag"><<span class="name">a</span> <span class="attr">href</span>=<span class="string">"{{ page.redirect_to }}"</span>></span>{{ page.redirect_to }}<span class="tag"></<span class="name">a</span>></span>⋯⋯<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><h4 id="重導向的配置"><a href="#重導向的配置" class="headerlink" title="重導向的配置"></a>重導向的配置</h4><p>在 <code>_redirects</code> 裡面建立一個 <code>template.markdown</code> 的檔案,這個檔案是用來建立重導向的配置。</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">layout: redirects</span><br><span class="line">title: "自定義標題"</span><br><span class="line">description: "自定義描述"</span><br><span class="line"><span class="section">redirect<span class="emphasis">_to: "https://hyd.ai/"</span></span></span><br><span class="line"><span class="emphasis"><span class="section">---</span></span></span><br></pre></td></tr></table></figure><h4 id="最終的檔案架構"><a href="#最終的檔案架構" class="headerlink" title="最終的檔案架構"></a>最終的檔案架構</h4><p>到這邊就準備好了,整個專案的檔案架構應該是這樣:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">├── 404.html</span><br><span class="line">├── Gemfile</span><br><span class="line">├── Gemfile.lock</span><br><span class="line">├── _config.yml</span><br><span class="line">├── _layouts</span><br><span class="line">│ └── redirects.html</span><br><span class="line">├── _redirects</span><br><span class="line">│ └── template.markdown</span><br><span class="line">└── index.markdown</span><br></pre></td></tr></table></figure><h3 id="修改設定來提供重導向服務"><a href="#修改設定來提供重導向服務" class="headerlink" title="修改設定來提供重導向服務"></a>修改設定來提供重導向服務</h3><h4 id="index-markdown"><a href="#index-markdown" class="headerlink" title="index.markdown"></a>index.markdown</h4><p>若有人訪問了此服務網站的首頁,我們至少可以將它導向到其他地方,比如個人的部落格。</p><p>在 <code>index.markdown</code> 裡面加入以下的內容:</p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">layout: redirects</span><br><span class="line">title: "hydai's blog"</span><br><span class="line">description: "hydaiの空想世界"</span><br><span class="line"><span class="section">redirect<span class="emphasis">_to: "https://hyd.ai/"</span></span></span><br><span class="line"><span class="emphasis"><span class="section">---</span></span></span><br></pre></td></tr></table></figure><h4 id="404-html"><a href="#404-html" class="headerlink" title="404.html"></a>404.html</h4><p>若有人訪問了不存在的縮網址,我們可以透過 404.html 來讓他轉到首頁或者其他指定的地方,如個人的部落格。</p><p>在 <code>404.html</code> 裡面加入以下的內容:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">permalink: /404.html</span><br><span class="line">layout: redirects</span><br><span class="line">title: "hydai's blog"</span><br><span class="line">description: "hydaiの空想世界"</span><br><span class="line">redirect_to: "https://hyd.ai/"</span><br><span class="line">---</span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">style</span> <span class="attr">type</span>=<span class="string">"text/css"</span> <span class="attr">media</span>=<span class="string">"screen"</span>></span><span class="language-css"></span></span><br><span class="line"><span class="language-css"> <span class="selector-class">.container</span> {</span></span><br><span class="line"><span class="language-css"> <span class="attribute">margin</span>: <span class="number">10px</span> auto;</span></span><br><span class="line"><span class="language-css"> <span class="attribute">max-width</span>: <span class="number">600px</span>;</span></span><br><span class="line"><span class="language-css"> <span class="attribute">text-align</span>: center;</span></span><br><span class="line"><span class="language-css"> }</span></span><br><span class="line"><span class="language-css"> <span class="selector-tag">h1</span> {</span></span><br><span class="line"><span class="language-css"> <span class="attribute">margin</span>: <span class="number">30px</span> <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css"> <span class="attribute">font-size</span>: <span class="number">4em</span>;</span></span><br><span class="line"><span class="language-css"> <span class="attribute">line-height</span>: <span class="number">1</span>;</span></span><br><span class="line"><span class="language-css"> <span class="attribute">letter-spacing</span>: -<span class="number">1px</span>;</span></span><br><span class="line"><span class="language-css"> }</span></span><br><span class="line"><span class="language-css"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">h1</span>></span>404<span class="tag"></<span class="name">h1</span>></span></span><br><span class="line"></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span><span class="tag"><<span class="name">strong</span>></span>Page not found :(<span class="tag"></<span class="name">strong</span>></span><span class="tag"></<span class="name">p</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">p</span>></span>The requested page could not be found.<span class="tag"></<span class="name">p</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><h4 id="清理不需要的相依性"><a href="#清理不需要的相依性" class="headerlink" title="清理不需要的相依性"></a>清理不需要的相依性</h4><p>由於這個縮網址服務不需要任何的主題與擴充元件,因此我們可以將 Gemfile 裡面用不到的相依性清除,如 <code>minima</code>, <code>jekyll-feed</code> 等。</p><p>以下是我最後的 Gemfile:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">source "https://rubygems.org"</span><br><span class="line"># Hello! This is where you manage which Jekyll version is used to run.</span><br><span class="line"># When you want to use a different version, change it below, save the</span><br><span class="line"># file and run `bundle install`. Run Jekyll with `bundle exec`, like so:</span><br><span class="line">#</span><br><span class="line"># bundle exec jekyll serve</span><br><span class="line">#</span><br><span class="line"># This will help ensure the proper Jekyll version is running.</span><br><span class="line"># Happy Jekylling!</span><br><span class="line">gem "jekyll", "~> 4.3.4"</span><br><span class="line"># If you want to use GitHub Pages, remove the "gem "jekyll"" above and</span><br><span class="line"># uncomment the line below. To upgrade, run `bundle update github-pages`.</span><br><span class="line"># gem "github-pages", group: :jekyll_plugins</span><br><span class="line">#</span><br><span class="line"># Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem</span><br><span class="line"># and associated library.</span><br><span class="line">platforms :mingw, :x64_mingw, :mswin, :jruby do</span><br><span class="line"> gem "tzinfo", ">= 1", "< 3"</span><br><span class="line"> gem "tzinfo-data"</span><br><span class="line">end</span><br><span class="line"></span><br><span class="line"># Performance-booster for watching directories on Windows</span><br><span class="line">gem "wdm", "~> 0.1", :platforms => [:mingw, :x64_mingw, :mswin]</span><br><span class="line"></span><br><span class="line"># Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem</span><br><span class="line"># do not have a Java counterpart.</span><br><span class="line">gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby]</span><br></pre></td></tr></table></figure><h4 id="修改-config-yml"><a href="#修改-config-yml" class="headerlink" title="修改 _config.yml"></a>修改 <code>_config.yml</code></h4><p>把基本的資訊都寫入 <code>_config.yml</code> 中,並且加上重導向相關的機制:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">title:</span> <span class="string">URL</span> <span class="string">shortener</span></span><br><span class="line"><span class="attr">email:</span> <span class="string">[email protected]</span></span><br><span class="line"><span class="attr">description:</span> <span class="string">>-</span> <span class="comment"># this means to ignore newlines until "baseurl:"</span></span><br><span class="line"> <span class="string">URL</span> <span class="string">shortener</span> <span class="string">for</span> <span class="string">hyd.ai</span></span><br><span class="line"><span class="attr">baseurl:</span> <span class="string">""</span> <span class="comment"># the subpath of your site, e.g. /blog</span></span><br><span class="line"><span class="attr">url:</span> <span class="string">"https://hyd.ai"</span> <span class="comment"># the base hostname & protocol for your site, e.g. http://example.com</span></span><br><span class="line"><span class="attr">twitter_username:</span> <span class="string">hydai_tw</span></span><br><span class="line"><span class="attr">github_username:</span> <span class="string">hydai</span></span><br><span class="line"></span><br><span class="line"><span class="attr">collections:</span></span><br><span class="line"> <span class="attr">redirects:</span></span><br><span class="line"> <span class="attr">output:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">permalink:</span> <span class="string">/:path/</span></span><br></pre></td></tr></table></figure><p>到此為止就是整個縮網址服務的建立流程,接下來就是部署的部分。</p><h3 id="部署到-GitHub-Pages"><a href="#部署到-GitHub-Pages" class="headerlink" title="部署到 GitHub Pages"></a>部署到 GitHub Pages</h3><p>在這個專案中,新增一個 workflows 的檔案 <code>jekyll.yml</code>,你可以取不同的名字,他將用來處理我們部署到 GitHub Pages 所用。</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 給個名字</span></span><br><span class="line"><span class="attr">name:</span> <span class="string">Deploy</span> <span class="string">Jekyll</span> <span class="string">site</span> <span class="string">to</span> <span class="string">Pages</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line"> <span class="comment"># Runs on pushes targeting the default branch</span></span><br><span class="line"> <span class="comment"># 只有在 commits 被推到 main 分支時才會觸發</span></span><br><span class="line"> <span class="attr">push:</span></span><br><span class="line"> <span class="attr">branches:</span> [<span class="string">"main"</span>]</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 允許你手動觸發這個 workflow</span></span><br><span class="line"> <span class="attr">workflow_dispatch:</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 設定 GITHUB_TOKEN 的權限,讓他可以部署到 GitHub Pages</span></span><br><span class="line"><span class="attr">permissions:</span></span><br><span class="line"> <span class="attr">contents:</span> <span class="string">read</span></span><br><span class="line"> <span class="attr">pages:</span> <span class="string">write</span></span><br><span class="line"> <span class="attr">id-token:</span> <span class="string">write</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果有多個部署在排隊,我們只會保留最新的來執行,但不會取消正在進行的部署</span></span><br><span class="line"><span class="attr">concurrency:</span></span><br><span class="line"> <span class="attr">group:</span> <span class="string">"pages"</span></span><br><span class="line"> <span class="attr">cancel-in-progress:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line"> <span class="attr">build:</span></span><br><span class="line"> <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line"> <span class="attr">steps:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Checkout</span></span><br><span class="line"> <span class="comment"># 將程式碼 checkout 到 runner 上</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">actions/checkout@v4</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Setup</span> <span class="string">Ruby</span></span><br><span class="line"> <span class="comment"># 設定 Ruby 環境</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">ruby/setup-ruby@v1</span></span><br><span class="line"> <span class="attr">with:</span></span><br><span class="line"> <span class="attr">ruby-version:</span> <span class="string">'3.3'</span></span><br><span class="line"> <span class="attr">bundler-cache:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">cache-version:</span> <span class="number">0</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Setup</span> <span class="string">Pages</span></span><br><span class="line"> <span class="attr">id:</span> <span class="string">pages</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">actions/configure-pages@v5</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Build</span> <span class="string">with</span> <span class="string">Jekyll</span></span><br><span class="line"> <span class="comment"># 預設會輸出到 './_site' 目錄</span></span><br><span class="line"> <span class="attr">run:</span> <span class="string">bundle</span> <span class="string">exec</span> <span class="string">jekyll</span> <span class="string">build</span> <span class="string">--baseurl</span> <span class="string">"$<span class="template-variable">{{ steps.pages.outputs.base_path }}</span>"</span></span><br><span class="line"> <span class="attr">env:</span></span><br><span class="line"> <span class="attr">JEKYLL_ENV:</span> <span class="string">production</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Upload</span> <span class="string">artifact</span></span><br><span class="line"> <span class="comment"># 預設會上傳 './_site' 目錄</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">actions/upload-pages-artifact@v3</span></span><br><span class="line"></span><br><span class="line"> <span class="attr">deploy:</span></span><br><span class="line"> <span class="attr">environment:</span></span><br><span class="line"> <span class="attr">name:</span> <span class="string">github-pages</span></span><br><span class="line"> <span class="attr">url:</span> <span class="string">${{</span> <span class="string">steps.deployment.outputs.page_url</span> <span class="string">}}</span></span><br><span class="line"> <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line"> <span class="attr">needs:</span> <span class="string">build</span></span><br><span class="line"> <span class="attr">steps:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">Deploy</span> <span class="string">to</span> <span class="string">GitHub</span> <span class="string">Pages</span></span><br><span class="line"> <span class="attr">id:</span> <span class="string">deployment</span></span><br><span class="line"> <span class="attr">uses:</span> <span class="string">actions/deploy-pages@v4</span></span><br></pre></td></tr></table></figure><h3 id="在-GitHub-上啟用-Pages"><a href="#在-GitHub-上啟用-Pages" class="headerlink" title="在 GitHub 上啟用 Pages"></a>在 GitHub 上啟用 Pages</h3><p>要注意的是,當將上面的 workflow 啟用後,如果以前在該 repo 上並沒有啟用過 GitHub Pages 的話,你需要到 <code>Settings</code> -> <code>Pages</code> 中啟用 GitHub Pages。</p><p>因為我們是使用 GitHub Pages 的服務,因此在 <code>Build and deployment</code> -> <code>Source</code> 中選擇 <code>GitHub Actions</code> 即可。</p><h3 id="使用自己的網域"><a href="#使用自己的網域" class="headerlink" title="使用自己的網域"></a>使用自己的網域</h3><p>如果你有自己的網域,同樣在 <code>Settings</code> -> <code>Pages</code> 中的 <code>Custom domain</code> 欄位把自己的子網域放上去。</p><h2 id="結語"><a href="#結語" class="headerlink" title="結語"></a>結語</h2><p>這個縮網址服務的建立流程其實非常簡單,只要有一點點的 HTML 與 markdown 的基礎,就可以輕鬆的建立一個屬於自己的縮網址服務。過程間也不需要去理解 Jekyll 的運作原理,只要知道怎麼建立版型與配置就可以了。</p>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>之前的縮網址服務我是使用 picsee 來做的,但在免費的方案中,並不支援 HTTPS,這個影響很大,如果在 URL 中存在 HTTPS 的話,轉址服務就會失效。</p>
<p>P.S. 因為我很不滿意 picsee 就不放上連結了,此外,我也非常不建議大家使用。</p>
<p>雖然有段時間可以使用 Cloudflare 的 Proxy 來讓他有 HTTPS 的樣子,可是某次更新後也失效了,而且我發現失效的時候是在演講前,因此當了盤子付了一千台幣買了一年的進階網址服務。</p>
<p>早知道這麼麻煩,當初應該在不緊急的時候先搬遷到 <a href="https://lihi.io/">lihi</a> 上面,畢竟都要付錢了,當然要找一家好一點的服務商。</p>
<p>然而,過了一段時間,我發現我其實不需要這麼多功能,只是想要一個簡單的縮網址服務而已,我並不需要追蹤成效,也不需要網址的統計,因為我唯一需要的功能就只是讓我的聽眾可以用短一點的網址拿到投影片或者是其他的資料。<br>在這時意外看到了 <a href="https://github.com/sitcon-tw/URL-Shortener">SITCON 的 URL-Shortener</a>,我發現這個服務就是我想要的。</p>
<p>在功能上:</p>
<ul>
<li>可以自訂網址</li>
<li>可以加上該網址的簡介</li>
<li>可以放圖片</li>
<li>全部都是 markdown 語法</li>
<li>可以用 GitHub workflow 來自動部署</li>
</ul>
<p>因此我就以他的專案為基礎,自己做了一個<a href="https://github.com/hydai/URL-Shortener">相似的縮網址服務</a></p></summary>
<category term="Note" scheme="https://hyd.ai/categories/Note/"/>
<category term="URL Shortener" scheme="https://hyd.ai/tags/URL-Shortener/"/>
</entry>
<entry>
<title>每次升級 mac os 總會遇到的 xcrun error invalid active developer path, missing xcurn at ...</title>
<link href="https://hyd.ai/2016/10/01/xcurn-error-after-upgrade-10-12/"/>
<id>https://hyd.ai/2016/10/01/xcurn-error-after-upgrade-10-12/</id>
<published>2016-10-01T12:21:30.000Z</published>
<updated>2024-11-19T05:51:10.421Z</updated>
<content type="html"><![CDATA[<p>每次升級總會遇上一次的 xcrun error ,<br>為了不要每次都查資料,<br>來把它記錄一下吧!</p><span id="more"></span><p>上次遇到好像是從 10.10 升級到 10.11 的時候,<br>同樣的這次從 10.11 升級到 10.12 也是遇到一樣的問題。</p><p>每次升級完以後,xcode 跟要抓取的 lib 好像就會跑掉,<br>當我在跑 <code>brew update</code> 的時候就會噴出下面這種 error:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ brew update</span><br><span class="line">xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools),</span><br><span class="line">missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun)</span><br></pre></td></tr></table></figure><p>要解決的方法很簡單,看到上面的關鍵字 <code>CommandLineTools</code>,<br>我們就把 xcode 的 CommandLineTools 裝上來就能解掉這個問題囉~</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xcode-select --install</span><br></pre></td></tr></table></figure><p>執行這行以後,他會問你要不要 <code>取得 xcode</code>,<br>如果你只是需要解掉這個問題,並沒有要使用 xcode 做開發的話,<br>直接選「安裝」即可,不安裝 xcode 的話,可以省下很多空間跟時間呢!</p>]]></content>
<summary type="html"><p>每次升級總會遇上一次的 xcrun error ,<br>為了不要每次都查資料,<br>來把它記錄一下吧!</p></summary>
<category term="Note" scheme="https://hyd.ai/categories/Note/"/>
<category term="MacOS" scheme="https://hyd.ai/tags/MacOS/"/>
<category term="xcurn" scheme="https://hyd.ai/tags/xcurn/"/>
</entry>
<entry>
<title>發 Pull Request 該注意的事情</title>
<link href="https://hyd.ai/2016/08/03/pullrequestnote/"/>
<id>https://hyd.ai/2016/08/03/pullrequestnote/</id>
<published>2016-08-03T14:06:22.000Z</published>
<updated>2024-11-19T03:00:10.630Z</updated>
<content type="html"><![CDATA[<h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>在漫長的程式旅途中,我們很容易就使用到 Free software(如 gcc) 以及<br>Open Source Project(如 Bootstrap) 。<br>身為用戶,我其實一直希望能為這些很棒的作品增加更多更棒的功能。</p><p>也許是身為工程師的浪漫吧,我很渴望能做出一款全世界都在用的軟體,<br>然後很自豪地說:「看呀,你在用的OOXX是我做的喔!」(燦笑)</p><p>而在這之前,我們可能更常碰到在使用 Open Source Project 的情況下遇到 Bug ,<br>或是想為其添加新功能。這時候,如果是在 GitHub 上頭,我們便會以 Pull Request<br>的方式把自己的修改發過去給 upstream 希望他們能把這樣的增進給 Merge 進去。</p><p>不過先別急著在改完就馬上送過去,不然可能很容易會被無視或是當成小白喔!</p><span id="more"></span><h2 id="1-至少要測試過才發-Pull-Request-過去喔"><a href="#1-至少要測試過才發-Pull-Request-過去喔" class="headerlink" title="1. 至少要測試過才發 Pull Request 過去喔"></a>1. 至少要測試過才發 Pull Request 過去喔</h2><p>千萬不要把沒有測試過的 Code 就直接發 Pull Request 塞過去,<br>這個一定會被巴死,而且人家會覺得你腦袋壞掉OTZ</p><p>現在很多的 Project 都會串上 CI 當你發送 Pull Request 過去時,<br>便會驅動 CI 進行測試,如果你的程式碼根本沒有通過測試,那麼 Project 的<br>maintainer 當然不會去幫你看囉。</p><p>也因此很容易就直接被忽略了。<br>而且這樣的行為可能會讓別人對你留下不是很好的印象喔!!</p><h2 id="2-符合人家的文化"><a href="#2-符合人家的文化" class="headerlink" title="2. 符合人家的文化"></a>2. 符合人家的文化</h2><p>正所謂家有家規、國有國法,當你想要為一個 Project 發送 Pull Request 的時候,<br>千萬要注意自己的 Coding Style 有沒有符合規範、命名的方式有沒有跟人家一致等等。</p><p>通常可以在人家的 Project 底下找到 CONTRIBUTING.md 或是 contributing guide ,<br>這裡面通常會記載很詳細的你要如何融入這個貢獻群的方式,<br>有些也會在這邊說明 Project 裡頭的 Coding Style 甚至是 Naming Style 喔!</p><p>如果沒有在 Project 中找到這些文化資訊的話,那麼就要利用自己 <em>敏銳</em> 的觀察力,<br>仔細的看一下該個 Project 裡面是怎麼樣的撰寫風格,然後盡量去符合 Code Owner 的<br>風格吧!</p><h2 id="3-要隨時跟想-merge-進去的-branch-保持同步"><a href="#3-要隨時跟想-merge-進去的-branch-保持同步" class="headerlink" title="3. 要隨時跟想 merge 進去的 branch 保持同步"></a>3. 要隨時跟想 merge 進去的 branch 保持同步</h2><p>比如說今天你在 fork 過來的 Project 從他的 <code>develop</code> branch 拉出來一條<br>叫做 <code>new_feature_A</code> 的 branch,準備為這個 Project 新增一個新功能 A。</p><p>在非常認真的撰寫程式碼後,你終於完成了這個新功能 A,並且想要把它貢獻回去原本的<br>Project 中,這時候你可能會想發一個 Pull Request(PR) 想把你的 <code>new_feature_A</code><br>branch merge 到原開發者的 <code>develop</code> 的 branch 上。</p><p>但是那條你原先拉出來的 <code>develop</code> branch 可能已經有了更多的 commit 或是<br>merge 了許多的 PR。<br>於是你的 branch 跟原開發者的 branch 就會發生 conflict,沒辦法被原開發者使用自動<br> merge,因為會被 conflict 的情況卡住。</p><p>當然這時候原開發者沒有義務幫你解決這個 conflict 的問題,如果你沒有自己處理好,<br>原開發者可能也會直接不理這個 PR 了。</p><p>因此隨時與自己想要貢獻回去的 branch 同步也是很重要的喔!</p><p>通常我個人的同步做法是這樣的:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git fetch upstream</span><br><span class="line">git checkout new_feature_A <span class="comment"># 切到自己開發的那條 branch 上</span></span><br><span class="line">git rebase upstream/develop <span class="comment"># 跟原開發者的 develop branch 做 rebase</span></span><br></pre></td></tr></table></figure><p>不使用 git merge 跟 upstream 同步,而是用 rebase 的方式,<br>這樣可以保持整條 branch 的乾淨程度喔。</p><p>而到後來我自己很不喜歡看到 merge commit 這個點出現XD<br>畢竟有時候太多的 merge commit 實在會讓整個圖不太好看。</p><p>所以我自己會盡量少用 <code>git pull</code> 或是 <code>git merge</code> 這兩個指令的話,<br>而是改用 <code>git pull --rebase</code> 跟 <code>git rebase</code> 來取代喔!</p><h2 id="4-Squash-commits-的重要性"><a href="#4-Squash-commits-的重要性" class="headerlink" title="4. Squash commits 的重要性"></a>4. Squash commits 的重要性</h2><p>平常我們在開發的時候,很常進行 commit ,雖然只是要完成一件事情,<br>可是卻花了好幾個 commit 來完成這件事。最常見的是下面這個模樣:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">commit 1: Add feature meow</span><br><span class="line">commit 2: Fix typo</span><br><span class="line">commit 3: Fix missing OO</span><br><span class="line">commit 4: Fix bugs in feature meow</span><br><span class="line">...</span><br></pre></td></tr></table></figure><p>但是如果你要送上去的重點只有「Add feature meow」這件事情,我認為就應該只留下<br>表達出 「Add feature meow」 這件事的 commit log 就好,<br>這些細節(繁瑣)的過程留在 commit log 裡也沒有太大的好處。</p><p>這個時候我們就可以透過 <code>git rebase -i</code> 的方式來做 squash commits 讓我們的<br>commit log 變得更乾淨。</p><p>至於要怎麼使用 <code>git rebase</code> 來做 squash 呢?就留待之後的文章再來好好解釋啦!</p><p>P.S. 本文是以個人的經驗撰寫而成,<br>如果缺漏或需更正之處,歡迎各位提出更多的建議喔OuO。</p>]]></content>
<summary type="html"><h2 id="0-前言"><a href="#0-前言" class="headerlink" title="0. 前言"></a>0. 前言</h2><p>在漫長的程式旅途中,我們很容易就使用到 Free software(如 gcc) 以及<br>Open Source Project(如 Bootstrap) 。<br>身為用戶,我其實一直希望能為這些很棒的作品增加更多更棒的功能。</p>
<p>也許是身為工程師的浪漫吧,我很渴望能做出一款全世界都在用的軟體,<br>然後很自豪地說:「看呀,你在用的OOXX是我做的喔!」(燦笑)</p>
<p>而在這之前,我們可能更常碰到在使用 Open Source Project 的情況下遇到 Bug ,<br>或是想為其添加新功能。這時候,如果是在 GitHub 上頭,我們便會以 Pull Request<br>的方式把自己的修改發過去給 upstream 希望他們能把這樣的增進給 Merge 進去。</p>
<p>不過先別急著在改完就馬上送過去,不然可能很容易會被無視或是當成小白喔!</p></summary>
<category term="Note" scheme="https://hyd.ai/categories/Note/"/>
<category term="git" scheme="https://hyd.ai/tags/git/"/>
<category term="Pull Request" scheme="https://hyd.ai/tags/Pull-Request/"/>
<category term="PR" scheme="https://hyd.ai/tags/PR/"/>
</entry>
<entry>
<title>發現新玩具,用 Hexo 來寫網誌吧!</title>
<link href="https://hyd.ai/2016/05/22/helloworld/"/>
<id>https://hyd.ai/2016/05/22/helloworld/</id>
<published>2016-05-22T08:21:11.000Z</published>
<updated>2024-11-19T03:00:10.630Z</updated>
<content type="html"><![CDATA[<h1 id="準備更新網誌"><a href="#準備更新網誌" class="headerlink" title="準備更新網誌"></a>準備更新網誌</h1><p>長時間以來都是用 Google blogger 跟 logdown 兩個服務來寫網誌,<br>但是一個不吃 markdown 語法,只能用傳統的編輯,<br>另一個則是不是很穩,有時候會炸掉。</p><p>剛好發現這個工具 Hexo 可以用 markdown 來寫網誌,而且可以跟 GitHub Page 做結合,<br>那就來試用看看吧!</p><span id="more"></span><h1 id="一些渲染測試"><a href="#一些渲染測試" class="headerlink" title="一些渲染測試"></a>一些渲染測試</h1><h1 id="h1"><a href="#h1" class="headerlink" title="h1"></a>h1</h1><h2 id="h2"><a href="#h2" class="headerlink" title="h2"></a>h2</h2><h3 id="h3"><a href="#h3" class="headerlink" title="h3"></a>h3</h3><h4 id="h4"><a href="#h4" class="headerlink" title="h4"></a>h4</h4><p><strong>Bold</strong></p><p><em>Italy</em></p><p><em><strong>BI</strong></em></p><p><code>Pusheen</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># bash</span></span><br><span class="line">$ <span class="built_in">echo</span> “Meow”</span><br><span class="line">$ <span class="built_in">cd</span> ~</span><br></pre></td></tr></table></figure><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// cpp</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>{</span><br><span class="line"> std::cout << “hello, world\n”;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">auto</span> i = <span class="number">0</span>; i < <span class="number">100</span>; i++) {</span><br><span class="line"> std::cout << i*<span class="number">100</span> << std::endl;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># python</span></span><br><span class="line">a = <span class="number">100</span></span><br><span class="line">b = <span class="number">1000</span></span><br><span class="line"><span class="keyword">if</span> a > <span class="number">100</span> <span class="keyword">and</span> b < <span class="number">50</span>:</span><br><span class="line"> <span class="built_in">print</span> (“Yes”)</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="準備更新網誌"><a href="#準備更新網誌" class="headerlink" title="準備更新網誌"></a>準備更新網誌</h1><p>長時間以來都是用 Google blogger 跟 logdown 兩個服務來寫網誌,<br>但是一個不吃 markdown 語法,只能用傳統的編輯,<br>另一個則是不是很穩,有時候會炸掉。</p>
<p>剛好發現這個工具 Hexo 可以用 markdown 來寫網誌,而且可以跟 GitHub Page 做結合,<br>那就來試用看看吧!</p></summary>
</entry>
</feed>