-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
535 lines (469 loc) · 56.6 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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title>xring's blog</title>
<link rel="self" type="application/atom+xml" href="https://xring.net/atom.xml"/>
<link rel="alternate" type="text/html" href="https://xring.net"/>
<generator uri="https://www.getzola.org/">Zola</generator>
<updated>2025-01-02T00:00:00+00:00</updated>
<id>https://xring.net/atom.xml</id>
<entry xml:lang="en">
<title>Rust 中的 LazyLock 和 OnceLock</title>
<published>2025-01-02T00:00:00+00:00</published>
<updated>2025-01-02T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/lazylock-and-once-lock-in-rust/"/>
<id>https://xring.net/lazylock-and-once-lock-in-rust/</id>
<content type="html" xml:base="https://xring.net/lazylock-and-once-lock-in-rust/"><p><code>LazyLock</code> 和 <code>OnceLock</code> 是 Rust 中用于实现惰性初始化的两种不同的锁机制。它们都可以用于延迟初始化某个值,直到第一次访问时才进行计算和存储。它们被视为对 <code>lazy_static</code> 和 <code>once_cell</code> 的现代替代方案,提供了更简洁和类型安全的接口。</p>
<pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::sync::LazyLock;
</span><span>
</span><span style="color:#b48ead;">static </span><span style="color:#d08770;">CONFIG</span><span>: LazyLock&lt;String&gt; = LazyLock::new(|| {
</span><span> </span><span style="color:#65737e;">// 运行时初始化逻辑
</span><span> println!(&quot;</span><span style="color:#a3be8c;">Initializing CONFIG...</span><span>&quot;);
</span><span> &quot;</span><span style="color:#a3be8c;">Runtime configuration</span><span>&quot;.</span><span style="color:#96b5b4;">to_string</span><span>()
</span><span>});
</span><span>
</span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() {
</span><span> </span><span style="color:#65737e;">// 第一次访问时进行初始化
</span><span> println!(&quot;</span><span style="color:#a3be8c;">Config: </span><span style="color:#d08770;">{}</span><span>&quot;, *</span><span style="color:#d08770;">CONFIG</span><span>);
</span><span> </span><span style="color:#65737e;">// 再次访问时不会重新初始化
</span><span> println!(&quot;</span><span style="color:#a3be8c;">Config: </span><span style="color:#d08770;">{}</span><span>&quot;, *</span><span style="color:#d08770;">CONFIG</span><span>);
</span><span>}
</span></code></pre>
<p><code>Initializing CONFIG...</code> 的内容只会被打印一次。</p>
<pre data-lang="rust" style="background-color:#2b303b;color:#c0c5ce;" class="language-rust "><code class="language-rust" data-lang="rust"><span style="color:#b48ead;">use </span><span>std::sync::OnceLock;
</span><span>
</span><span style="color:#b48ead;">static </span><span style="color:#d08770;">CONFIG</span><span>: OnceLock&lt;String&gt; = OnceLock::new();
</span><span>
</span><span style="color:#b48ead;">fn </span><span style="color:#8fa1b3;">main</span><span>() {
</span><span> </span><span style="color:#65737e;">// 第一次调用 get_or_init 时进行初始化
</span><span> </span><span style="color:#b48ead;">let</span><span> config = </span><span style="color:#d08770;">CONFIG</span><span>.</span><span style="color:#96b5b4;">get_or_init</span><span>(|| {
</span><span> println!(&quot;</span><span style="color:#a3be8c;">Initializing CONFIG...</span><span>&quot;);
</span><span> &quot;</span><span style="color:#a3be8c;">Runtime configuration</span><span>&quot;.</span><span style="color:#96b5b4;">to_string</span><span>()
</span><span> });
</span><span>
</span><span> println!(&quot;</span><span style="color:#a3be8c;">Config: </span><span style="color:#d08770;">{}</span><span>&quot;, config);
</span><span>
</span><span> </span><span style="color:#65737e;">// 再次调用 get_or_init 时不会重新初始化
</span><span> </span><span style="color:#b48ead;">let</span><span> config_again = </span><span style="color:#d08770;">CONFIG</span><span>.</span><span style="color:#96b5b4;">get_or_init</span><span>(|| {
</span><span> println!(&quot;</span><span style="color:#a3be8c;">This will not be printed.</span><span>&quot;);
</span><span> &quot;</span><span style="color:#a3be8c;">Another configuration</span><span>&quot;.</span><span style="color:#96b5b4;">to_string</span><span>()
</span><span> });
</span><span>
</span><span> println!(&quot;</span><span style="color:#a3be8c;">Config again: </span><span style="color:#d08770;">{}</span><span>&quot;, config_again);
</span><span>}
</span></code></pre>
<p>在已初始化的值上多次调用 <code>get_or_init</code> 不会重新初始化。</p>
<p><code>LazyLock</code></p>
<ul>
<li>线程安全性: LazyLock 使用内部的同步机制来确保初始化逻辑只会执行一次,即使在多个线程同时访问的情况下。它通常用于全局静态变量的惰性初始化。</li>
<li>使用场景: 适合在程序启动时就能确定初始化逻辑的场景,尤其是全局静态变量。</li>
</ul>
<p><code>OnceLock</code></p>
<ul>
<li>线程安全性: OnceLock 也使用同步机制来确保初始化逻辑只会执行一次。它提供了一个简单的 API 来在运行时进行初始化。</li>
<li>使用场景: 适合需要在运行时初始化的场景,尤其是在需要确保某个值只被初始化一次的情况下。</li>
</ul>
</content>
</entry>
<entry xml:lang="en">
<title>2024 总结</title>
<published>2024-12-31T00:00:00+00:00</published>
<updated>2024-12-31T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/2024-summary/"/>
<id>https://xring.net/2024-summary/</id>
<content type="html" xml:base="https://xring.net/2024-summary/"><p>今天最后一天了,水一个年终总结。2024算是一个 <code>gap year</code>了,给自己放松了差不多三个月的时间,做了一些思考,也尝试了一些之前从未试过的东西。</p>
<h2 id="gong-zuo-fang-mian">工作方面</h2>
<p>掰手指算了一下,“创业”第六年了。在这个团队里有过太多的从0到1,有过太多的造轮子。早几天跟小伙伴们聊起了从追求一个9到两个9到三个9,从网关 rt 500ms 到 80ms,也算是“小有成就”了。</p>
<h3 id="tuan-dui-jian-she">团队建设</h3>
<p>作为年轻人聚集地,咱们还是比较稳的。今年有一位后端小伙伴离开,有一位之前离职的测试小伙伴回归。极度扁平,基本不需要团队管理。大家都在自己的位置做自己的事,吃着老板画的饼,大概都在想着明年会不一样吧。</p>
<h3 id="bian-cheng-yu-yan">编程语言</h3>
<p>和去年一样,Rust 依然是使用得最多的。今年把几个基础服务从 Go / Java 迁移到了 Rust,我一人一服务,从0到1,管它是不是轮子,能用就好,开心最重要。前端一如既往的烂,倒是尝试学习了一下 TypeScript,没有太多使用场景。然后复习了一下 Python 相关的,写了一些调用大模型的胶水代码。</p>
<h3 id="xi-tong-jia-gou">系统架构</h3>
<p>现在回想一下,在18年底就 all in 了 K8S 和 Istio,创业团队没有历史包袱还是舒服的。管它有没有坑,管它会不会,先上了再说。虽说一路踩坑填坑无数,但这玩意儿对于中小团队来说,走过一次基本到处可用了。</p>
<p>今年在系统架构层面没有太多变更,基础服务有的变动只有配置中心从 etcd 切换到了更轻量的自己造的轮子。春节假期后会做一些 K8S 和 Istio 的升级工作。</p>
<h3 id="ai-he-llm">AI 和 LLM</h3>
<p>内部使用的类 ChatGPT 平台经过了多次升级,陆续添加了 OpenAI、Claude、Gemini、DeepSeek 的支持,一年用掉了5000多美刀,看起来还是提升了效率的。</p>
<p>业务层面接入大模型也终于在下半年启动了,目前有两个场景在尝试中,更多的在路上。</p>
<p>自己也尝试在借用 AI 和 LLM 相关的做一些独立开发,希望能在明年发布一款自己从需求开始的产品吧。</p>
<p>近期比较多的精力在这一块了,做一些积累,计划明年在这块能有更多的产出。</p>
<h3 id="gong-ju">工具</h3>
<p>单独说一说 <a href="https://wakatime.com/@xring">WakaTime</a> 吧,一个记录“时间”的工作,个人觉得我还挺受用的。</p>
<h2 id="sheng-huo-fang-mian">生活方面</h2>
<p>先说说孩子,三岁了,10月份出生的,关于是否上幼儿园的问题跟家里人有一些争执,还是决定晚一些再上幼儿园。春节过后有一次比较严重的生病,去住了几天院,万幸恢复的较好。关于孩子的教育,我个人承行快乐教育,在最近购置了帐篷天幕等装备,希望能坚持户外陪伴。</p>
<p>然后说说媳妇儿,今年下半年换了工作,是她想要的“稳定”的工作。收入水平有所降低,但不重要,她开心就好了。另一个角度是有更多的时间陪孩子了。</p>
<p>父母身体状态良好,这个最重要。下半年给父母安排了一场北京游,给我爹安排了心心念念梅兰芳大剧院看京剧。明年上半年需要再安排一次全面体检了。相比父母辈,祖父母、外祖父母辈身体状态较多,也给我妈整的有些憔悴,此处有些槽点...</p>
<p>自己在生活上没有太多的变化,夏天有过一段时间的健身,没能每天坚持。唯一值得一提的是把英语学习当成了生活的一部分吧,在 Cambly 上了大概 83 节一对一的课,2500多分钟吧,口语能力有一些提升,明年需要更多的坚持。</p>
<p>今年给自己差不多放了三个月的假,想清了一些东西,也甩掉了一些标签。如果要做个总结,那大概就是 <code>做更好的自己</code> 吧。然后希望明年的总结有更多的内容可以写下。</p>
</content>
</entry>
<entry xml:lang="en">
<title>Mac 平台交叉编译 Rust 至 Linux 平台</title>
<published>2024-10-21T00:00:00+00:00</published>
<updated>2024-10-21T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/cross-compiling-rust-from-mac-to-linux/"/>
<id>https://xring.net/cross-compiling-rust-from-mac-to-linux/</id>
<content type="html" xml:base="https://xring.net/cross-compiling-rust-from-mac-to-linux/"><p>最近在用 Rust 开发一些提效小工具,在 Mac 平台编码但运行环境为 Linux(裸跑,非容器),将相关过程记录一下。</p>
<p>之前这种跨平台的编译是使用 <a href="https://github.com/cross-rs/cross">cross</a> 来完成的,使用类似下面的命令来进行编译:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">cross</span><span> build</span><span style="color:#bf616a;"> --release --target</span><span> x86_64-unknown-linux-gnu
</span></code></pre>
<p>本次直接用 cargo 来解决:</p>
<ul>
<li>使用 <code>rustup target add</code> 来添加目标平台的标准库</li>
<li>安装目标平台的 <code>链接器(linker)</code></li>
<li>配置 cargo 来使 <code>rustc</code> 能够使用正确的链接器</li>
<li>设置 <code>TARGET_CC</code> 环境变量</li>
<li>使用 <code>cargo build</code> 来进行编译</li>
</ul>
<h2 id="tian-jia-mu-biao-target">添加目标 target</h2>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">rustup</span><span> target add x86_64-unknown-linux-gnu
</span></code></pre>
<h2 id="an-zhuang-mu-biao-ping-tai-de-lian-jie-qi">安装目标平台的链接器</h2>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">brew</span><span> install SergioBenitez/osxct/x86_64-unknown-linux-gnu
</span></code></pre>
<h2 id="tian-jia-cargo-pei-zhi-wen-jian">添加 cargo 配置文件</h2>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">mkdir</span><span> .cargo
</span><span style="color:#bf616a;">touch</span><span> config.toml
</span></code></pre>
<p>添加下面的配置文件:</p>
<pre data-lang="toml" style="background-color:#2b303b;color:#c0c5ce;" class="language-toml "><code class="language-toml" data-lang="toml"><span>[target.x86_64-unknown-linux-gnu]
</span><span style="color:#bf616a;">linker </span><span>= &quot;</span><span style="color:#a3be8c;">x86_64-unknown-linux-gnu-gcc</span><span>&quot;
</span></code></pre>
<h2 id="she-zhi-huan-jing-bian-liang">设置环境变量</h2>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#b48ead;">export </span><span style="color:#bf616a;">TARGET_CC</span><span>=</span><span style="color:#a3be8c;">x86_64-unknown-linux-gnu-gcc
</span></code></pre>
<h2 id="kai-shi-bian-yi">开始编译</h2>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">cargo</span><span> build</span><span style="color:#bf616a;"> --release --target</span><span> x86_64-unknown-linux-gnu
</span></code></pre>
<p>设置环境变量和编译可以在同一步进行:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">TARGET_CC</span><span>=</span><span style="color:#a3be8c;">x86_64-unknown-linux-gnu-gcc </span><span style="color:#bf616a;">cargo</span><span> build</span><span style="color:#bf616a;"> --release --target</span><span> x86_64-unknown-linux-gnu
</span></code></pre>
<p>然后在 <code>./target/x86_64-unknown-linux-gnu/release/</code> 可以找到编译产物。</p>
<h2 id="yun-xing-huan-jing-glibc-ban-ben-guo-di-wen-ti">运行环境 glibc 版本过低问题</h2>
<p>当在运行环境执行 <code>./tool-name</code> 时,部分服务器报错了:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">./tool-name:</span><span> /lib64/libc.so.6: version GLIBC_2.25&#39;</span><span style="color:#a3be8c;"> not found (required by ./tool-name)
</span></code></pre>
<p>查看 ldd 版本:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">ldd --version
</span><span style="color:#bf616a;">ldd</span><span> (GNU libc) </span><span style="color:#bf616a;">2.17
</span><span style="color:#bf616a;">Copyright</span><span> (C) </span><span style="color:#bf616a;">2012</span><span> Free Software Foundation, Inc.
</span></code></pre>
<p>这是因为 <code>glibc</code> 版本较低(部分服务器运行好多年了,一直未替换),此时可以升级版本或者使用静态链接方案。升级版本考虑的问题比较多,下面继续看使用静态链接来编译。</p>
<p>当 target 是 <code>x86_64-unknown-linux-gnu</code> 时,会使用<code>动态链接</code>,也就是在运行时来链接。因此会出现运行环境 glibc 版本不满足要求的情况。换用 <code>x86_64-unknown-linux-musl</code> 这个目标平台来解决问题。</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># 添加目标平台
</span><span style="color:#bf616a;">rustup</span><span> target add x86_64-unknown-linux-musl
</span><span style="color:#65737e;"># 安装链接器
</span><span style="color:#bf616a;">brew</span><span> install FiloSottile/musl-cross/musl-cross
</span></code></pre>
<p>然后在 cargo 配置文件 <code>.cargo/config.toml</code> 中添加如下内容:</p>
<pre data-lang="toml" style="background-color:#2b303b;color:#c0c5ce;" class="language-toml "><code class="language-toml" data-lang="toml"><span>[target.x86_64-unknown-linux-musl]
</span><span style="color:#bf616a;">linker </span><span>= &quot;</span><span style="color:#a3be8c;">x86_64-linux-musl-gcc</span><span>&quot;
</span><span style="color:#65737e;"># -static-pie 如果不支持,则再添加下面这一行
</span><span style="color:#65737e;"># rustflags = [&quot;-C&quot;, &quot;link-args=-static&quot;]
</span></code></pre>
<p>最后执行编译:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">TARGET_CC</span><span>=</span><span style="color:#a3be8c;">x86_64-linux-musl-gcc </span><span style="color:#bf616a;">cargo</span><span> build</span><span style="color:#bf616a;"> --release --target</span><span> x86_64-unknown-linux-musl
</span></code></pre>
<p>在 <code>./target/x86_64-unknown-linux-musl/release/</code> 可以找到编译产物。这样得到的可执行文件就是通过静态链接的了,应该在大部分的 Linux 上都可以执行。</p>
</content>
</entry>
<entry xml:lang="en">
<title>在 Cargo 项目中使用 git 仓库作为依赖</title>
<published>2024-03-28T00:00:00+00:00</published>
<updated>2024-03-28T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/cargo-dependencies-from-git/"/>
<id>https://xring.net/cargo-dependencies-from-git/</id>
<content type="html" xml:base="https://xring.net/cargo-dependencies-from-git/"><p>在 Cargo 项目中,最简单的依赖方式为:</p>
<pre data-lang="toml" style="background-color:#2b303b;color:#c0c5ce;" class="language-toml "><code class="language-toml" data-lang="toml"><span>[dependencies]
</span><span style="color:#bf616a;">serde </span><span>= &quot;</span><span style="color:#a3be8c;">1</span><span>&quot;
</span></code></pre>
<p>这会直接使用 <a href="https://crates.io/">crates.io</a> 的依赖和版本,某些时候可能需要从源码仓库直接依赖某个分支或者依赖未发布到 <a href="https://crates.io/">crates.io</a> 。此时,最小化的配置为:</p>
<pre data-lang="toml" style="background-color:#2b303b;color:#c0c5ce;" class="language-toml "><code class="language-toml" data-lang="toml"><span>[dependencies]
</span><span style="color:#bf616a;">regex </span><span>= { </span><span style="color:#bf616a;">git </span><span>= &quot;</span><span style="color:#a3be8c;">https://github.com/rust-lang/regex.git</span><span>&quot; }
</span><span>
</span></code></pre>
<p>如果需要指定分支,可以配置为:</p>
<pre data-lang="toml" style="background-color:#2b303b;color:#c0c5ce;" class="language-toml "><code class="language-toml" data-lang="toml"><span>[dependencies]
</span><span style="color:#bf616a;">regex </span><span>= { </span><span style="color:#bf616a;">git </span><span>= &quot;</span><span style="color:#a3be8c;">https://github.com/rust-lang/regex.git</span><span>&quot;, </span><span style="color:#bf616a;">branch </span><span>= &quot;</span><span style="color:#a3be8c;">next</span><span>&quot; }
</span><span>
</span></code></pre>
<p>上面两种使用基于 HTTPS 的认证,如果项目是非开仓库,需要进行额外配置,参考<a href="https://doc.rust-lang.org/cargo/appendix/git-authentication.html#https-authentication">这里</a></p>
<p>另外一种是基于 SSH 的认证,此时相关配置格式为:</p>
<pre data-lang="toml" style="background-color:#2b303b;color:#c0c5ce;" class="language-toml "><code class="language-toml" data-lang="toml"><span>[dependencies]
</span><span style="color:#bf616a;">regex </span><span>= { </span><span style="color:#bf616a;">git </span><span>= &quot;</span><span style="color:#a3be8c;">ssh://[email protected]/user/repo.git</span><span>&quot; }
</span></code></pre>
<p>基于 SSH 的认证要求 <code>ssh-agent</code>,可以使用下面的方式快速添加:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span># 注意 SSH 的私钥位置
</span><span>ssh-add ~/.ssh/id_rsa
</span></code></pre>
<p>使用 <code>ssh-add -l</code> 来确认密钥已经成功添加到 <code>ssh-agent</code>。</p>
<p>如果 SSH 密钥是有密码的,这个步骤需要输入密码。通过 <code>ssh-agent</code> 后续 Cargo 访问私仓时将不需要输入密码。</p>
<p>当 Git 仓库中的代码更新了,使用以下命令来更新本地依赖的代码:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>cargo update
</span></code></pre>
</content>
</entry>
<entry xml:lang="en">
<title>使用 Gmail 实现域名邮箱收发功能</title>
<published>2023-04-06T00:00:00+00:00</published>
<updated>2023-04-06T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/send-receive-email-with-cf-gmail-and-custom-domain/"/>
<id>https://xring.net/send-receive-email-with-cf-gmail-and-custom-domain/</id>
<content type="html" xml:base="https://xring.net/send-receive-email-with-cf-gmail-and-custom-domain/"><p>业界良心 Cloudflare 提供了很多实用的功能,其中之一就是 Email Routing,可以用来便捷的将自定义域名邮箱收到的邮件转发到某个目标邮箱。再配合上 Gmail 的一些设置,即可以轻松实现使用 Gmail 来收和发域名邮箱的邮件。</p>
<blockquote>
<p>域名需要在 Cloudflare 或者使用 Cloudflare 的 Nameserver</p>
</blockquote>
<h2 id="shou-you-jian">收邮件</h2>
<ul>
<li>在 Cloudflare 的控制台,选择配置 Email --&gt; Email Routing --&gt; Routes</li>
<li>添加 自定义邮箱地址 [email protected]</li>
<li>然后选择转发的<code>目标邮箱地址</code>即可。</li>
</ul>
<p>可以在 Destination addresses 处添加多个 目标邮箱地址。目标邮箱地址在第一次添加时需要进行验证操作。</p>
<p>通过上面的配置,发送到 [email protected] 的邮件会被转发到配置的 目标邮箱地址,但是在 Gmail 回复邮件的时候仍然使用 目标邮箱地址。需要继续下面的配置才能将回信发件人地址修改为 [email protected]。</p>
<h2 id="fa-you-jian">发邮件</h2>
<ul>
<li>需要 Gmail 开启了 2FA,https://myaccount.google.com/signinoptions/two-step-verification</li>
<li>创建一个 Gmail 的 App 密码,https://security.google.com/settings/security/apppasswords 分别选择 Mail 和 Mac 两个选项后生成,得到密码 <code>ABC</code></li>
<li>在 Gmail 页面,打开 see all settings --&gt; Accounts and Import --&gt; Send mail as --&gt; add another email address</li>
<li>填写表单的第一步 Email Address 填写 [email protected],即自定义域名邮箱</li>
<li>填写表单的第二步 SMTP Server 填写 http://smtp.gmail.com,用户名填写 gmail 邮箱地址,密码填写上面得到的 ABC</li>
<li>添加账户,然后在写信或者回信时就可以选择 [email protected]</li>
</ul>
<p>也可以在 Send mail as 处勾选 <code>Reply from the same address the message was sent to</code> 这样回信的时候就默认使用收信的地址了。</p>
<p>配置好上面两个部分,就完成了使用 Gmail 来收和发域名邮箱的邮件。</p>
</content>
</entry>
<entry xml:lang="en">
<title>Xcode 15.2 安装 iOS_17.2_Simulator</title>
<published>2023-01-23T00:00:00+00:00</published>
<updated>2023-01-23T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/xcode-15-2-install-ios-17-2-simulator/"/>
<id>https://xring.net/xcode-15-2-install-ios-17-2-simulator/</id>
<content type="html" xml:base="https://xring.net/xcode-15-2-install-ios-17-2-simulator/"><p>更新 Xcode 到 15.2 之后,需要安装iOS_17.2_Simulator,但是在 Xcode 里下载总是网络错误,或者下载卡在 99% 的地方,可以用如下步骤来手动安装。</p>
<p>打开官网 <a href="https://developer.apple.com/download/all/?q=ios">https://developer.apple.com/download/all/?q=ios</a>,登录后选择下载 <code>iOS 17.2 Simulator Runtime.dmg</code> 文件。</p>
<p>假设文件存储到 <code>~/Downloads</code>,在终端依次执行下面的命令:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#65737e;"># 下面这条命令需要输入密码
</span><span style="color:#bf616a;">sudo</span><span> xcode-select</span><span style="color:#bf616a;"> -s</span><span> /Applications/Xcode.app
</span><span>
</span><span style="color:#bf616a;">xcodebuild -runFirstLaunch
</span><span>
</span><span style="color:#65737e;"># 需要替换为自己的路径,下面这条命令需要一些时间来执行
</span><span style="color:#65737e;"># 执行完成终端会有输出,且会弹窗提示 &quot;Verifying...&quot;
</span><span style="color:#bf616a;">xcrun</span><span> simctl runtime add &#39;</span><span style="color:#a3be8c;">/Users/xring/Downloads/iOS_17.2_Simulator_Runtime.dmg</span><span>&#39;
</span></code></pre>
<p>然后在 Xcode 就可以看到 iOS_17.2_Simulator 了。</p>
</content>
</entry>
<entry xml:lang="en">
<title>博客迁移至 Zola</title>
<published>2023-01-21T00:00:00+00:00</published>
<updated>2023-01-21T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/blog-upgraded-to-zola/"/>
<id>https://xring.net/blog-upgraded-to-zola/</id>
<content type="html" xml:base="https://xring.net/blog-upgraded-to-zola/"><p>从19年参与“创业”至今,已经很长时间没有停下来做一些思考和总结了,也有很长时间没有将学的知识、踩的坑、买的教训等等来沉淀一下。TODO 里面记录了很多想要系统学习的内空,有书籍有视频有博客等等,很多时间脑子懂了不代表手懂了,那就多做一些记录吧。</p>
<p>于是,博客迁移到 Rust 实现的 <a href="https://www.getzola.org/">Zola</a>,选择了一个简单的主题 <a href="https://github.com/pawroman/zola-theme-terminimal">terminimal</a>,主题参照 <a href="https://heitorpb.github.io/">Heitor's Log</a> 进行了简单的装修 ,再搭配了一个基于 GitHub Discussions 的评论系统 <a href="https://github.com/apps/giscus">giscus</a>。基本就可以用起来了,等需要的时候再去折腾一下图床,就可以用来承载内容了。</p>
<p>站点美容告一段落,希望每个月至少有两篇输出吧。</p>
<p>自勉。</p>
</content>
</entry>
<entry xml:lang="en">
<title>Istio 中配置 Envoy 获取 Client 真实 IP</title>
<published>2019-03-22T00:00:00+00:00</published>
<updated>2019-03-22T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/istio-gateway-get-client-ip/"/>
<id>https://xring.net/istio-gateway-get-client-ip/</id>
<content type="html" xml:base="https://xring.net/istio-gateway-get-client-ip/"><p>背景:使用 Istio Ingress Gateway(Envoy),需要获取客户端真实 IP 地址</p>
<p>使用 Helm 安装 Istio 会安装一个名为 <code>istio-ingressgateway</code> 的 Service,类型为 <code>LoadBalancer</code>,可以将服务暴露到公网。 </p>
<p>这个 Service 的 <code>spec.externalTrafficPolicy</code> 默认值是 <code>Cluster</code>,我们只要将这个值更新为<code>Local</code>,就可以在 <code>X-Forwarded-For</code> 请求头获取到客户端真实 IP 地址了。</p>
</content>
</entry>
<entry xml:lang="en">
<title>Kubernetes 从私有镜像仓库拉取镜像</title>
<published>2019-01-11T00:00:00+00:00</published>
<updated>2019-01-11T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/k8s-pull-images-from-private-registry/"/>
<id>https://xring.net/k8s-pull-images-from-private-registry/</id>
<content type="html" xml:base="https://xring.net/k8s-pull-images-from-private-registry/"><p>在企业内部使用 private registry 来存储私有镜像显然是必需的,本例的私仓使用 <a href="https://github.com/goharbor/harbor">Harbor</a>,下面来看看在 Kubernetes 集群中怎么配置使用我们建立的私有镜像仓库。假设私有镜像仓库地址为:<code>https://hub.xring.info</code>,我们要用的镜像为 nginx:v0.1.0,存在仓库 mynginx 中。如果使用 docker pull 来拉取镜像则命令为:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>docker pull hub.xring.info/mynginx/nginx:v0.1.0
</span></code></pre>
<p>为了在 Kubernetes 中使用私有镜像仓库,我们需要做两个事:</p>
<ul>
<li>创建一个存储了私有镜像 credential 信息的 Secret 资源对象</li>
<li>在 Pod 创建模板使用 spec.imagePullSecrets 中指定创建的 Secret 对象</li>
</ul>
<!--more-->
<h3 id="chuang-jian-secret-zi-yuan-dui-xiang">创建 Secret 资源对象</h3>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>kubectl create secret docker-registry my-hub-secret --docker-server=hub.xring.info --docker-username=xbot --docker-password=123456 [email protected]
</span></code></pre>
<h3 id="zhi-ding-secret-dui-xiang">指定 Secret 对象</h3>
<p>以下面的 Pod 资源定义为例:</p>
<pre data-lang="yml" style="background-color:#2b303b;color:#c0c5ce;" class="language-yml "><code class="language-yml" data-lang="yml"><span style="color:#bf616a;">apiVersion</span><span>: </span><span style="color:#a3be8c;">v1
</span><span style="color:#bf616a;">kind</span><span>: </span><span style="color:#a3be8c;">Pod
</span><span style="color:#bf616a;">metadata</span><span>:
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">nginx-v010
</span><span> </span><span style="color:#bf616a;">labels</span><span>:
</span><span> </span><span style="color:#bf616a;">app</span><span>: </span><span style="color:#a3be8c;">nginx-v010
</span><span style="color:#bf616a;">spec</span><span>:
</span><span> </span><span style="color:#bf616a;">imagePullSecrets</span><span>:
</span><span> - </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">my-hub-secret
</span><span> </span><span style="color:#bf616a;">containers</span><span>:
</span><span> - </span><span style="color:#bf616a;">image</span><span>: </span><span style="color:#a3be8c;">hub.xring.info/mynginx/nginx:v0.1.0
</span><span> </span><span style="color:#bf616a;">name</span><span>: </span><span style="color:#a3be8c;">nginx-v010
</span></code></pre>
<p>然后再使用 <code>kubectl apply -f mynginx.yaml</code> 来创建 Pod 对象,就可以从私有镜像仓库中拉取镜像了。</p>
</content>
</entry>
<entry xml:lang="en">
<title>Maven 设置 HTTP 代理</title>
<published>2017-02-10T00:00:00+00:00</published>
<updated>2017-02-10T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/maven-setup-http-proxy/"/>
<id>https://xring.net/maven-setup-http-proxy/</id>
<content type="html" xml:base="https://xring.net/maven-setup-http-proxy/"><p>有时候基于公司安全因素考虑或者由于一些特殊原因,Maven 无法正常访问外部仓库来下载所需要的资源。这种情况下,可以通过为 Maven 配置 HTTP 代理来解决问题。</p>
<p>通过以下步骤来为 Maven 配置 HTTP 代理:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>- 获取 HTTP 代理信息
</span><span>- 找到 Maven 配置文件 settings.xml
</span><span>- 将代理信息添加到配置文件
</span></code></pre>
<p>假设我们有如下 HTTP 代理信息:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>host: 9.30.123.123
</span><span>port: 3712
</span><span>username: xring
</span><span>password: volcano
</span></code></pre>
<p>下一步来寻找 Maven 配置文件。<code>settimgs.xml</code> 文件可能存在于两个位置:
– ~/.m2/settings.xml
– M2_HOME/conf/settings.xml</p>
<p>如果 <code>~/.m2/settings.xml</code> 文件存在,则 <code>优先</code> 使用这个文件进行配置,如果不存在则需要使用 <code>M2_HOME/conf/settings.xml</code> 文件。如果没有配置 <code>M2_HOME</code> 这个环境变量或者忘记了 Maven 的安装位置,可以通过 <code>mvn -version</code> 可以找到 Maven home 目录,即上面提到的 <code>M2_HOME</code>,在 Mac 下得到类似输出:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">mvn -version
</span><span style="color:#bf616a;">...
</span><span style="color:#bf616a;">Maven</span><span> home: /usr/local/Cellar/maven/3.3.9/libexec
</span><span style="color:#bf616a;">...
</span></code></pre>
<p>则 <code>settimgs.xml</code> 文件就在 <code>/usr/local/Cellar/maven/3.3.9/libexec/conf</code> 目录中。</p>
<p>编辑找到的 settings.xml 文件,搜索 proxies 关键字,找到类似下面的这一段:</p>
<pre data-lang="xml" style="background-color:#2b303b;color:#c0c5ce;" class="language-xml "><code class="language-xml" data-lang="xml"><span>&lt;</span><span style="color:#bf616a;">proxies</span><span>&gt;
</span><span> </span><span style="color:#65737e;">&lt;!-- proxy
</span><span style="color:#65737e;"> | Specification for one proxy, to be used in connecting to the network.
</span><span style="color:#65737e;"> |
</span><span style="color:#65737e;"> &lt;proxy&gt;
</span><span style="color:#65737e;"> &lt;id&gt;optional&lt;/id&gt;
</span><span style="color:#65737e;"> &lt;active&gt;true&lt;/active&gt;
</span><span style="color:#65737e;"> &lt;protocol&gt;http&lt;/protocol&gt;
</span><span style="color:#65737e;"> &lt;username&gt;proxyuser&lt;/username&gt;
</span><span style="color:#65737e;"> &lt;password&gt;proxypass&lt;/password&gt;
</span><span style="color:#65737e;"> &lt;host&gt;proxy.host.net&lt;/host&gt;
</span><span style="color:#65737e;"> &lt;port&gt;80&lt;/port&gt;
</span><span style="color:#65737e;"> &lt;nonProxyHosts&gt;local.net|some.host.com&lt;/nonProxyHosts&gt;
</span><span style="color:#65737e;"> &lt;/proxy&gt;
</span><span style="color:#65737e;"> --&gt;
</span><span>&lt;/</span><span style="color:#bf616a;">proxies</span><span>&gt;
</span></code></pre>
<p>在 proxies 下可以配置多个 proxy 元素,如果声明了多个 proxy 元素,则默认情况下第一个被激活的 proxy 元素会被使用。
当 proxy 元素里的 active 被设置为 true 时表示该 proxy 处于激活状态。
id 字段是 proxy 元素的一个标识
当代理不需要认证时,username 和 password 可以被注释掉
nonProxyHost 元素用来指定哪些主机名不需要代理,当有多个主机名不需要代理时用 | 来分隔主机名,主机名里支持通配符(如 *.google.com)。</p>
<p>了解了这段 XML 各元素的意义后将得到的 HTTP 代理信息依次填入相应元素:</p>
<pre data-lang="xml" style="background-color:#2b303b;color:#c0c5ce;" class="language-xml "><code class="language-xml" data-lang="xml"><span>&lt;</span><span style="color:#bf616a;">proxies</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">proxy</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">id</span><span>&gt;volcano-proxy&lt;/</span><span style="color:#bf616a;">id</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">active</span><span>&gt;true&lt;/</span><span style="color:#bf616a;">active</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">protocol</span><span>&gt;http&lt;/</span><span style="color:#bf616a;">protocol</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">username</span><span>&gt;xring&lt;/</span><span style="color:#bf616a;">username</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">password</span><span>&gt;volcano&lt;/</span><span style="color:#bf616a;">password</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">host</span><span>&gt;9.30.123.123&lt;/</span><span style="color:#bf616a;">host</span><span>&gt;
</span><span> &lt;</span><span style="color:#bf616a;">port</span><span>&gt;3712&lt;/</span><span style="color:#bf616a;">port</span><span>&gt;
</span><span> </span><span style="color:#65737e;">&lt;!--
</span><span style="color:#65737e;"> &lt;nonProxyHosts&gt;local.net|some.host.com&lt;/nonProxyHosts&gt;
</span><span style="color:#65737e;"> --&gt;
</span><span> &lt;/</span><span style="color:#bf616a;">proxy</span><span>&gt;
</span><span>&lt;/</span><span style="color:#bf616a;">proxies</span><span>&gt;
</span></code></pre>
<p>保存 <code>settings.xml</code> 配置文件,Maven 配置 HTTP 代理完成。</p>
</content>
</entry>
<entry xml:lang="en">
<title>Docker 手动迁移镜像</title>
<published>2017-02-02T00:00:00+00:00</published>
<updated>2017-02-02T00:00:00+00:00</updated>
<author>
<name>
xring
</name>
</author>
<link rel="alternate" type="text/html" href="https://xring.net/docker-manually-transfer-image/"/>
<id>https://xring.net/docker-manually-transfer-image/</id>
<content type="html" xml:base="https://xring.net/docker-manually-transfer-image/"><p>使用公共或者私有的 Registry 可以方便的将 Docker 镜像进行转移,在某些场景可能期望手动来迁移镜像。</p>
<p>此时可以使用 <code>docker save</code> 和 <code>docker load</code> 指令将镜像打包然后在其它位置加载回来。这里使用 nginx 镜像来做演示,将镜像从一台机器手动迁移到另一台机器。</p>
<!--more-->
<h3 id="da-bao-jing-xiang">打包镜像</h3>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">docker</span><span> save</span><span style="color:#bf616a;"> -o</span><span> nginx.tar nginx:latest
</span></code></pre>
<p>然后 <code>nginx:latest</code> 镜像被打包为 <code>nginx.tar</code> 文件,此时可以通过 scp 之类的方法传输这个镜像文件。</p>
<blockquote>
<p>在打包过程中可以使用类似 <code>docker save nginx | gzip &gt; nginx.tar.gz</code> 的命令进行压缩减小文件体积。</p>
</blockquote>
<p>更多参数请参考 <a href="https://docs.docker.com/engine/reference/commandline/save/">官方文档</a> 对此命令的说明。</p>
<h3 id="jia-zai-jing-xiang">加载镜像</h3>
<p>在另一台没有 <code>nginx:latest</code> 镜像的机器上执行:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">docker</span><span> load</span><span style="color:#bf616a;"> -i</span><span> nginx.tar
</span><span style="color:#65737e;"># 下面为命令输出
</span><span style="color:#bf616a;">3358360aedad:</span><span> Loading layer </span><span style="color:#b48ead;">[</span><span>==================================================&gt;</span><span style="color:#b48ead;">]</span><span> 58.44MB/58.44MB
</span><span style="color:#bf616a;">c632afbadb38:</span><span> Loading layer </span><span style="color:#b48ead;">[</span><span>==================================================&gt;</span><span style="color:#b48ead;">]</span><span> 53.91MB/53.91MB
</span><span style="color:#bf616a;">180ab8f004dc:</span><span> Loading layer </span><span style="color:#b48ead;">[</span><span>==================================================&gt;</span><span style="color:#b48ead;">]</span><span> 3.584kB/3.584kB
</span></code></pre>
<p>执行完成后 <code>nginx:latest</code> 镜像就被手动迁移到了另一台机器上。</p>
<p>更多参数请参考 <a href="https://docs.docker.com/engine/reference/commandline/load/">官方文档</a> 对此命令的说明。</p>
</content>
</entry>
</feed>