-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.xml
7023 lines (6226 loc) · 371 KB
/
index.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
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Kryptonite Lab</title>
<link>https://szthanatos.github.io/</link>
<atom:link href="https://szthanatos.github.io/index.xml" rel="self" type="application/rss+xml" />
<description>Kryptonite Lab</description>
<generator>Wowchemy (https://wowchemy.com)</generator><language>zh-Hans</language><copyright>© 2021 szthanatos</copyright><lastBuildDate>Mon, 28 Dec 2020 19:03:14 +0800</lastBuildDate>
<image>
<url>https://szthanatos.github.io/media/icon_hu638af3a55c65206eddec4e3c4c13a753_187410_512x512_fill_lanczos_center_2.png</url>
<title>Kryptonite Lab</title>
<link>https://szthanatos.github.io/</link>
</image>
<item>
<title>Docker -01- 基本概念</title>
<link>https://szthanatos.github.io/series/docker/basis/</link>
<pubDate>Wed, 05 Dec 2018 22:17:22 +0800</pubDate>
<guid>https://szthanatos.github.io/series/docker/basis/</guid>
<description><h2 id="docker-简介">Docker 简介</h2>
<h3 id="什么是-docker">什么是 Docker</h3>
<p>Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,并于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 <a href="https://github.com/moby/moby" target="_blank" rel="noopener">GitHub</a> 上进行维护,后来还加入了 Linux 基金会,并成立推动 <a href="https://www.opencontainers.org/" target="_blank" rel="noopener">开放容器联盟(OCI)</a>。</p>
<p>Docker 最初是在 Ubuntu 12.04 上以 <a href="https://golang.org/" target="_blank" rel="noopener">Go 语言</a> 进行开发实现的, Red Hat 则从 RHEL 6.5 开始对 Docker 进行支持 (换句话说不支持 CentOS6.5 以下)。</p>
<p>Docker 是一种 <strong>容器化技术</strong> ,类似虚拟机的概念,但不同的是传统虚拟机是在虚拟硬件的基础上,完整模拟一整个操作系统,而 Docker 是以单个应用(容器)为单位进行虚拟。</p>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/17/PFhKS4M68AO7BVQ.png" alt="传统虚拟化" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/17/a2Hp1ZVJoIA4Ocv.png" alt="Docker" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<h3 id="docker-特点">Docker 特点</h3>
<p>Docker 具有以下特点:</p>
<ul>
<li><strong>文件系统隔离</strong> :每个进程容器运行在完全独立的根文件系统里。</li>
<li><strong>资源隔离</strong> :可以使用 cgroup 为每个进程容器分配不同的系统资源,例如 CPU 和内存。</li>
<li><strong>网络隔离</strong> :每个进程容器运行在自己的网络命名空间里,拥有自己的虚拟接口和 IP 地址。</li>
<li><strong>写时复制</strong> :采用写时复制方式创建根文件系统,这让部署变得极其快捷,并且节省内存和硬盘空间。</li>
<li><strong>日志记录</strong> :Docker 将会收集和记录每个进程容器的标准流(stdout/stderr/stdin),用于实时检索或批量检索。</li>
<li><strong>变更管理</strong> :容器文件系统的变更可以提交到新的映像中,并可重复使用以创建更多的容器。无需使用模板或手动配置。</li>
<li><strong>交互式 Shell</strong> :Docker 可以分配一个虚拟终端并关联到任何容器的标准输入上,例如运行一个一次性交互 shell。</li>
</ul>
<h3 id="为什么要使用-docker">为什么要使用 Docker</h3>
<table>
<thead>
<tr>
<th style="text-align:left">特性</th>
<th style="text-align:left">容器</th>
<th style="text-align:left">虚拟机</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">启动</td>
<td style="text-align:left">秒级</td>
<td style="text-align:left">分钟级</td>
</tr>
<tr>
<td style="text-align:left">硬盘使用</td>
<td style="text-align:left">一般为 <code>MB</code></td>
<td style="text-align:left">一般为 <code>GB</code></td>
</tr>
<tr>
<td style="text-align:left">性能</td>
<td style="text-align:left">接近原生</td>
<td style="text-align:left">弱于原生</td>
</tr>
<tr>
<td style="text-align:left">系统支持量</td>
<td style="text-align:left">单机支持上千个容器</td>
<td style="text-align:left">一般几十个</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>更高效的利用系统资源</strong> :由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。</li>
<li><strong>更快速的启动时间</strong> :Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。</li>
<li><strong>一致的运行环境</strong> : Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 <em>「这段代码在我机器上没问题啊」</em> 这类问题。</li>
<li><strong>持续交付和部署</strong> :对 <code>DevOps</code> 人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 <a href="###Dockerfile">Dockerfile</a> 来进行镜像构建,并结合 <code>持续集成 (Continuous Integration)</code> 系统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 <code>持续部署 (Continuous Delivery/Deployment)</code> 系统进行自动部署。</li>
<li><strong>更轻松的迁移</strong> :由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。</li>
</ul>
<h2 id="基本概念">基本概念</h2>
<p>Docker 包括三个基本概念</p>
<ul>
<li>镜像(<code>Image</code>)</li>
<li>容器(<code>Container</code>)</li>
<li>仓库(<code>Repository</code>)</li>
</ul>
<p>理解了这三个概念,就理解了 Docker 的整个生命周期。</p>
<h3 id="镜像">镜像</h3>
<p>操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 <code>root</code> 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 <code>root</code> 文件系统。比如官方镜像 <code>ubuntu:16.04</code> 就包含了完整的一套 Ubuntu 16.04 最小系统的 <code>root</code> 文件系统。</p>
<p>Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 <strong>镜像不包含任何动态数据,其内容在构建之后也不会被改变。</strong></p>
<p>严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。</p>
<p><strong>镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。</strong> 比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。</p>
<p>分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。</p>
<h3 id="容器">容器</h3>
<p>镜像(<code>Image</code>)和容器(<code>Container</code>)的关系,就像是面向对象程序设计中的 <code>类</code> 和 <code>实例</code> 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。</p>
<p><strong>容器的实质是进程</strong> ,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 <code>命名空间</code>。因此容器可以拥有自己的 <code>root</code> 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性,很多人初学 Docker 时常常会混淆容器和虚拟机。</p>
<p>前面讲过镜像使用的是分层存储,容器也是如此。 <strong>每一个容器运行时,是以镜像为基础层,在其上创建一个当前容器的存储层,</strong> 我们可以称这个为容器运行时读写而准备的存储层为 <strong>容器存储层</strong> 。</p>
<p>容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此, <strong>任何保存于容器存储层的信息都会随容器删除而丢失</strong> 。</p>
<p>按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。 <strong>所有的文件写入操作,都应该使用 [数据卷(Volume)](#### 方式 1:数据卷(推荐))、或者 [绑定宿主目录](#### 方式 2:挂载主机目录)</strong> ,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。</p>
<p>数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。</p>
<h3 id="仓库">仓库</h3>
<p>如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker 提供注册服务器 (<code>Docker Registry</code>) 来实现这样的服务。</p>
<p>一个 <code>Docker Registry</code> 中可以包含多个 <strong>仓库</strong> (<code>Repository</code>);每个仓库可以包含多个 <strong>标签</strong> (<code>Tag</code>);每个标签对应一个镜像。</p>
<p>通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <code>&lt;仓库名&gt;:&lt; 标签 &gt;</code> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 <code>latest</code> 作为默认标签。</p>
<p>以 <a href="https://store.docker.com/images/ubuntu" target="_blank" rel="noopener">Ubuntu 镜像</a> 为例,<code>ubuntu</code> 是仓库的名字,其内包含有不同的版本标签,如,<code>14.04</code>, <code>16.04</code>。我们可以通过 <code>ubuntu:14.04</code>,或者 <code>ubuntu:16.04</code> 来具体指定所需哪个版本的镜像。如果忽略了标签,比如 <code>ubuntu</code>,那将视为 <code>ubuntu:latest</code>。</p>
<p>仓库名经常以 <em>两段式路径</em> 形式出现,比如 <code>jwilder/nginx-proxy</code>,前者往往意味着 Docker Registry 多用户环境下的用户名,后者则往往是对应的软件名。但这并非绝对,取决于所使用的具体 Docker Registry 的软件或服务。</p>
<p>类似 git 和 GitHub,官方提供 <a href="https://hub.docker.com/" target="_blank" rel="noopener">Docker Hub</a>,作为默认的 Registry。用户也可以在本地搭建私有 Docker Registry。Docker 官方提供了 <a href="https://store.docker.com/images/registry/" target="_blank" rel="noopener">Docker Registry</a> 镜像,可以直接使用做为私有 Registry 服务。</p>
<h3 id="生命周期">生命周期</h3>
<p>结合上面的概念,这里有一张图比较好的概括了整个 Docker 工作的生命周期(以及主要命令)。
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/17/RIZ3S8jPrgBo5ve.png" alt="生命周期" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<h2 id="安装配置">安装配置</h2>
<p>这里仅以 CentOS 安装 Docker CE 举例说明。详见 <a href="https://docs.docker.com/engine/installation/linux/docker-ce/centos/" target="_blank" rel="noopener">Docker 官方 CentOS 安装文档</a></p>
<h3 id="准备工作">准备工作</h3>
<h4 id="系统要求">系统要求</h4>
<p>Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10。 CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功能(如 <code>overlay2</code> 存储层驱动)无法使用,并且部分功能可能不太稳定。</p>
<blockquote>
<p>警告:切勿在没有配置 Docker YUM 源的情况下直接使用 yum 命令安装 Docker.</p>
</blockquote>
<h4 id="卸载旧版本">卸载旧版本</h4>
<p>旧版本的 Docker 称为 <code>docker</code> 或者 <code>docker-engine</code>,使用以下命令卸载旧版本:</p>
<pre><code class="language-bash">sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
</code></pre>
<h3 id="使用脚本安装非生产环境">使用脚本安装(非生产环境)</h3>
<p>对于个人测试,可以使用这个脚本自动化安装 Docker:</p>
<pre><code class="language-bash">curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.sh
</code></pre>
<p>但是,需要注意, <strong>这个脚本可能扰乱你的系统配置、安装及大量的(你可能用不到的)依赖,并且只能安装最新(可能未经充分测试的)版本的 Docker</strong> , 所以不推荐在生产环境中使用。</p>
<h3 id="使用-yum-安装">使用 yum 安装</h3>
<p>安装依赖包:</p>
<pre><code class="language-bash">sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
</code></pre>
<p>添加 <code>yum</code> 软件源:</p>
<pre><code class="language-bash"># 中国科学技术大学开源软件镜像源
sudo yum-config-manager \
--add-repo \
https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
# 官方源
# sudo yum-config-manager \
# --add-repo \
# https://download.docker.com/linux/centos/docker-ce.repo
</code></pre>
<p>更新 <code>yum</code> 软件源缓存,并安装 <code>docker-ce</code>。</p>
<pre><code class="language-bash">sudo yum makecache fast
sudo yum install docker-ce
</code></pre>
<h3 id="离线安装">离线安装</h3>
<p>以 docker-ce-18.03.1 为例:</p>
<ol>
<li>在 <code>https://download.docker.com/linux/centos/7/x86_64/stable/Packages/</code> 这里找到对应 rpm 包</li>
<li>执行安装命令:<code>rpm -ivh docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm</code></li>
<li>由于安装环境不同,可能会发现缺少一些相关依赖包(eg: libcgroup、libtool-ltdl、container-selinux)前往 <code>https://pkgs.org/</code> 或 <code>https://buildlogs.centos.org/</code> 下载对应依赖包,依次安装即可</li>
</ol>
<h3 id="启动-docker-ce">启动 Docker CE</h3>
<pre><code class="language-bash">sudo systemctl enable docker
sudo systemctl start docker
</code></pre>
<h3 id="建立-docker-用户组">建立 Docker 用户组</h3>
<p>默认情况下,docker 命令需要 <code>root</code> 权限,为了避免每次输入命令都要加 <code>sudo</code>,可以将用户加入 <code>docker</code> 用户组:</p>
<pre><code class="language-bash">sudo groupadd docker
sudo usermod -aG docker $USER
</code></pre>
<p>退出当前终端并重新登录,进行如下测试。</p>
<h3 id="测试-docker-是否安装正确">测试 Docker 是否安装正确</h3>
<p>执行</p>
<pre><code class="language-bash">docker run hello-world
</code></pre>
<p>Docker 会从官方仓库下载 hello-world 镜像并启动,如果一切正常的话会看到类似如下提示:</p>
<pre><code class="language-bash">Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete
Digest: sha256:be0cd392e45be79ffeffa6b05338b98ebb16c87b255f48e297ec7f98e123905c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the &quot;hello-world&quot; image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
</code></pre>
<h3 id="镜像加速">镜像加速</h3>
<p>鉴于国内网络问题,建议使用 Docker 中国或者其他国内镜像源。</p>
<p>修改(或新增)<code>/etc/docker/daemon.json</code> 文件,添加:</p>
<pre><code class="language-bash">{
&quot;registry-mirrors&quot;: [&quot;https://registry.docker-cn.com&quot;]
}
</code></pre>
<p>之后重启 Docker 使配置生效。</p>
<h3 id="常用-docker-操作">常用 Docker 操作</h3>
<pre><code class="language-bash"># 查看 docker 版本
docker version
# 显示 docker 系统的信息
docker info
# 日志信息
docker logs
# 故障检查
service docker status
# 启动关闭 docker
sudo service docker start|stop
</code></pre>
<h2 id="使用镜像">使用镜像</h2>
<h3 id="基本操作">基本操作</h3>
<p>以 redis 为例,我们从 <a href="https://hub.docker.com/explore/" target="_blank" rel="noopener">Docker Hub</a> 上获取官方镜像到本地:</p>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/17/rxgkEdmeJuSHX38.jpg" alt="Docker hub redis" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<pre><code class="language-bash">docker pull redis
</code></pre>
<p><em>ps1:</em> 由于 redis 是官方源(Official),否则应该写完整的两段式仓库名 <code>&lt;用户名&gt;/&lt; 软件名 &gt;</code>,例如 bitnami/redis。</p>
<p><em>ps2:</em> 此处没有指定镜像版本,默认会拉取 redis:lastest 镜像,指定版本应该写成例如:redis:5.0-rc5</p>
<p>查看已经下载的镜像:</p>
<pre><code class="language-bash">docker image ls
# 会有类似如下显示
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 5f515359c7f8 5 days ago 183 MB
......
</code></pre>
<p>更细节的显示可以使用 <code>docker image ls --format &quot;{{.ID}}: {{.Repository}}&quot;</code> 直接列出镜像 ID 和仓库名,</p>
<p>或者使用 <code>docker image ls --format &quot;table {{.ID}}\t{{.Repository}}\t{{.Tag}}&quot;</code>
以表格等距显示.</p>
<p>如果要删除某个镜像的话,可以使用 <code>docker image rm {IMAGE ID}|{REPOSITORY}</code> 命令,不要过先确保没有容器在使用这个镜像。</p>
<h3 id="dockerfile">Dockerfile</h3>
<p>除了引用制作好的镜像,我们也可以基于现有镜像定制新的镜像。定制所用的脚本文件就是 Dockerfile。</p>
<p>Dockerfile 是一个文本文件,其内包含了一条条的 <strong>指令 (Instruction)</strong> ,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。</p>
<p>我们新建一个空白文件,命名为 <code>dockerfile</code>,再文件中写入如下内容:</p>
<pre><code class="language-dockerfile">FROM redis
RUN mkdir redis
WORKDIR redis
COPY ./redis.conf /etc/
CMD [&quot;redis-server&quot;, &quot;/etc/redis.conf&quot;]
</code></pre>
<p>我们依次解释上面每一行:</p>
<ul>
<li><strong>FROM</strong> 就是指定 <strong>基础镜像</strong> , 一个 <code>Dockerfile</code> 中 <code>FROM</code> 是必备的指令,并且必须是第一条指令。如果不以任何镜像为基础,那应该用 <code>FROM scratch</code> 作为起始指令。</li>
<li><strong>RUN</strong> 是 Dockerfile 的核心指令,用于执行一条命令,由于 Dockerfile 每一条指令都会新建一层,所以应该尽量将执行的内容写在一行(多行内容可以通过在末尾加 <code>\</code> 以表示未结束),它有两种写法:
<ul>
<li><strong>shell</strong> 格式:<code>RUN &lt;命令&gt;</code>,就像直接在命令行中输入的命令一样。</li>
<li><strong>exec</strong> 格式:<code>RUN [&quot;可执行文件&quot;, &quot;参数 1&quot;, &quot;参数 2&quot;]</code>,这更像是函数调用中的格式。</li>
</ul>
</li>
<li><strong>WORKDIR</strong> 表示指定当前工作目录,相当于 <code>cd</code> 命令。</li>
<li><strong>COPY</strong> 即复制文件到容器中,在这里是把 redis.conf 文件复制到容器的 <code>/etc</code> 目录下。</li>
<li><strong>CMD</strong> 是启动程序的命令,写法和 <code>RUN</code> 相同,一般推荐使用 <code>exec</code> 格式。</li>
</ul>
<p>常用 Docker 指令列表如下:</p>
<table>
<thead>
<tr>
<th>指令</th>
<th>含义</th>
<th>用法</th>
</tr>
</thead>
<tbody>
<tr>
<td>FROM</td>
<td>指定基础镜像</td>
<td><code>FROM &lt;基础镜像&gt;</code></td>
</tr>
<tr>
<td>RUN</td>
<td>执行指令</td>
<td><code>RUN [&quot;可执行文件&quot;, &quot;参数 1&quot;, &quot;参数 2&quot;]</code></td>
</tr>
<tr>
<td>COPY</td>
<td>复制文件</td>
<td><code>COPY [&quot;&lt; 源路径 1&gt;&quot;,... &quot;&lt; 目标路径 &gt;&quot;]</code></td>
</tr>
<tr>
<td>ADD</td>
<td>更高级的复制文件</td>
<td><code>ADD &quot;&lt;压缩文件&gt;&quot;</code></td>
</tr>
<tr>
<td>CMD</td>
<td>容器启动命令</td>
<td><code>CMD [&quot;可执行文件&quot;, &quot;参数 1&quot;, &quot;参数 2&quot;...]</code></td>
</tr>
<tr>
<td>ENTRYPOINT</td>
<td>入口点</td>
<td><code>ENTRYPOINT [&quot;可执行文件&quot;, &quot;参数 1&quot;, &quot;参数 2&quot;]</code></td>
</tr>
<tr>
<td>ENV</td>
<td>设置环境变量</td>
<td><code>ENV &lt;key1&gt;=&lt;value1&gt; &lt;key2&gt;=&lt;value2&gt;...</code></td>
</tr>
<tr>
<td>ARG</td>
<td>构建参数</td>
<td><code>ARG &lt;参数名&gt;[=&lt; 默认值 &gt;]</code></td>
</tr>
<tr>
<td>VOLUME</td>
<td>定义匿名卷</td>
<td><code>VOLUME [&quot;&lt; 路径 1&gt;&quot;, &quot;&lt; 路径 2&gt;&quot;...]</code></td>
</tr>
<tr>
<td>EXPOSE</td>
<td>暴露端口</td>
<td><code>EXPOSE &lt;端口 1&gt; [&lt; 端口 2&gt;...]</code></td>
</tr>
<tr>
<td>WORKDIR</td>
<td>指定工作目录</td>
<td><code>WORKDIR &lt;工作目录路径&gt;</code></td>
</tr>
<tr>
<td>USER</td>
<td>指定当前用户</td>
<td><code>USER &lt;用户名&gt;</code></td>
</tr>
<tr>
<td>HEALTHCHECK</td>
<td>健康检查</td>
<td>`HEALTHCHECK NONE</td>
</tr>
<tr>
<td>ONBUILD</td>
<td>构建下级镜像</td>
<td><code>ONBUILD &lt;其它指令&gt;</code></td>
</tr>
<tr>
<td>MAINTAINER</td>
<td>指定作者</td>
<td><code>ONBUILD &lt;作者&gt;</code></td>
</tr>
</tbody>
</table>
<p>更多指令及用法请参照 <a href="https://docs.docker.com/engine/reference/builder" target="_blank" rel="noopener">官方文档</a></p>
<p>如上,我们完成了一个使用自己配置文件的 redis 镜像的准备工作,之后依据这个 Dockerfile 进行构建:</p>
<pre><code class="language-bash">docker build -t redis_test:v0.1 .
# 会有类似如下输出:
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM redis
...
...
Removing intermediate container 9cdc27646c7b
Successfully built 44aa4490ce2c
</code></pre>
<p><code>docker build</code> 的用法为:</p>
<pre><code class="language-bash">docker build [选项] &lt; 上下文路径 / URL/-&gt;
</code></pre>
<p>最后,可以使用 <code>docker push</code> 将你自己构建的镜像上传到仓库中,详细用法见 <a href="https://docs.docker.com/engine/reference/commandline/push/" target="_blank" rel="noopener">官方文档 push</a></p>
<h2 id="容器操作">容器操作</h2>
<h3 id="容器启停">容器启停</h3>
<p>我们可以用这样的方式从之前的镜像启动一个容器:</p>
<pre><code class="language-bash">docker run -d --name some-redis redis
</code></pre>
<p><code>docker run</code> 的用法为 <code>docker run [选项] 镜像 [命令] [参数...]</code>,其中:</p>
<p><code>--name</code> 指定容器的名称, <code>-d</code> 指定后台运行,其他常用参数包括 <code>-i</code> 交互式操作,<code>-t</code> 使用终端(<code>it</code> 一般同时使用),<code>--rm</code> 容器退出后随之将其删除,完整参数列表可以通过 <code>--help</code> 或者 <a href="https://docs.docker.com/engine/reference/commandline/run/" target="_blank" rel="noopener">在线文档 docker run</a> 查看</p>
<p>由于我们是在后台运行,使用 <code>docker container ls</code> 来查看容器相关情况,如果要查看停止的进程,后面需要增加参数 <code>-a</code>:</p>
<pre><code class="language-bash">docker container ls
# 会看到类似如下内容
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
77b2dc01fe0f redis:v2 redis-server redis.conf 'while tr 2 minutes ago Up 1 minute agitated_wright
</code></pre>
<p>使用 <code>docker container stop</code> 来结束容器的运行:</p>
<pre><code class="language-bash">docker container stop 77b2dc01fe0f
</code></pre>
<p>类似的,使用 <code>docker container start | restart | stop</code> 可以控制容器的启停,
使用 <code>docker container rm</code> 来删除指定容器。</p>
<h3 id="数据管理">数据管理</h3>
<p>之前提到过,随着容器的销毁,容器内的数据也会一同丢失。为了保存数据,Docker 提供了两种方式(还有一种 tmpfs mountsb 不常用到):</p>
<h4 id="方式-1数据卷推荐">方式 1:数据卷(推荐)</h4>
<p>数据卷 <code>volume</code> 是一个可供一个或多个容器使用的特殊目录,它不依赖于 Unix 文件系统,也拥有独立于容器的生命周期。</p>
<p>创建一个数据卷:</p>
<pre><code class="language-bash">docker volume create my-vol
</code></pre>
<p>查看数据卷及具体信息:</p>
<pre><code class="language-bash"># 查看所有的数据卷
docker volume ls
# 会看到类似如下内容
local my-vol
# -----------------------------------
# 查看具体卷的信息
docker volume inspect my-vol
# 会看到类似如下内容
[
{
&quot;Driver&quot;: &quot;local&quot;,
&quot;Labels&quot;: {},
&quot;Mountpoint&quot;: &quot;/var/lib/docker/volumes/my-vol/_data&quot;,
&quot;Name&quot;: &quot;my-vol&quot;,
&quot;Options&quot;: {},
&quot;Scope&quot;: &quot;local&quot;
}
]
</code></pre>
<p>在用 docker run 的时候,增加 <code>--mount</code> 参数来使用数据卷, 还是以启动 redis 为例,这里我们启动 redis 并且开启 aof 持久化:</p>
<pre><code class="language-bash">docker run -d \
--name redis \
--mount source=my-vol,target=/data \
# -v my-vol:/data \
redis \
redis-server --appendonly yes
</code></pre>
<p>在这里 redis 产生的数据(<code>/data</code> 目录下)被挂载到数据卷 <code>my-vol</code> 中。</p>
<p>我们也可以使用 <code>-v</code> 或者 <code>--volume</code> 语法,但是 <a href="https://docs.docker.com/storage/volumes/#choose-the--v-or---mount-flag" target="_blank" rel="noopener">官方建议</a> 尽量使用 <code>--mount</code>。</p>
<p>同样使用 <code>inspect</code> 语法,我们可以查看 redis 容器的信息:</p>
<pre><code class="language-bash">docker inspect redis
# 会看到类似如下内容
&quot;Mounts&quot;: [
{
&quot;Type&quot;: &quot;volume&quot;,
&quot;Name&quot;: &quot;my-vol&quot;,
&quot;Source&quot;: &quot;/var/lib/docker/volumes/my-vol/_data&quot;,
&quot;Destination&quot;: &quot;/data&quot;,
&quot;Driver&quot;: &quot;local&quot;,
&quot;Mode&quot;: &quot;&quot;,
&quot;RW&quot;: true,
&quot;Propagation&quot;: &quot;&quot;
}
],
</code></pre>
<h4 id="方式-2绑定主机目录">方式 2:绑定主机目录</h4>
<p>我们也可以直接将容器的数据挂载 <code>bind mount</code> 到宿主机的目录或文件 (而非由 Docker 创建的数据卷), 以当前目录 <code>$(pwd)</code> 为例:</p>
<pre><code class="language-bash">docker run -d \
--name redis \
--mount type=bind,source=&quot;$(pwd)&quot;/target,target=/data \
redis \
redis-server --appendonly yes
</code></pre>
<p>挂载单独文件的方法类似。</p>
<p>需要注意,本地目录必须存在,否则会报错。</p>
<h4 id="区别">区别</h4>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/17/RdvIuVZhr6Jc5ax.png" alt="types of mounts volume" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<p>Volumes 是由 Docker 创建和管理,存储在宿主机固定位置(在 linux 上是 / var/lib/docker/volumes/)。 <strong>非 Docker 应用程序不能改动这一位置的数据。</strong> 一个数据卷可以同时被挂载到几个容器中。即使没有正在运行的容器使用这个数据卷,它依然不会清除。可以通过 <code>docker volume prune</code> 清除不再使用的数据卷。</p>
<p>Bind mounts 的数据可以存放在宿主机的任何地方。 <strong>非 Docker 应用程序可以改变这些数据。</strong></p>
<h3 id="使用网络">使用网络</h3>
<h4 id="端口映射">端口映射</h4>
<p><code>docker run</code> 的时候使用 <code>-P</code>(&ndash;publish-all) 参数,随机映射一个 49000~49900 的端口到内部容器开放的网络端口。</p>
<p>或者使用 <code>-p ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort</code>(&ndash;publish) 来指定具体端口映射:</p>
<pre><code class="language-bash">docker run -d \
--name some-redis \
-p 6379:6379 \
-p 127.0.0.1::16379/udp
-p 127.0.0.1:80:80
redis
</code></pre>
<p>这里我们分别将容器的 6379 端口映射到宿主机 <strong>任意 ip 的 6379 端口</strong> ,容器的 16379 udp 端口映射到宿主机的 <strong>任意端口</strong> ,容器的 80 端口映射到宿主机 <strong>对应的 80 端口</strong> 。</p>
<p>使用 <code>docker port</code> 可以查看对应容器的全部端口映射。</p>
<h4 id="容器互联">容器互联</h4>
<p>简单的容器互联可以通过 <code>--link</code> 实现,但是 <strong>官方未来可能会删除这个参数</strong> ,所以不展开。</p>
<p>最新的方式是搭建 docker 网络实现容器互联,先创建一个新的 Docker 网络:</p>
<pre><code class="language-bash">docker network create -d bridge my-net
</code></pre>
<p>这里的 <code>-d</code> 参数指定网络类型,常用的只有 bridge,其他的可能会在 Swarm 用到, 如果不知道 Swarm 是什么就不用在意。</p>
<p>以 redis 客户端 / 服务端为例,分别在启动的时候将之加入 <code>my-net</code> 网络:</p>
<pre><code class="language-bash">docker run -d \
--name redis-server \
--network my-net \
redis
docker run -it \
--rm \
--name redis-client \
--network my-net \
redis redis-cli -h redis-server
</code></pre>
<p>可以看到成功进入 redis-cli 客户端,我们可以尝试 <code>info</code>/<code>keys *</code> 或者其他命令查看 redis 服务端运行情况。</p>
<h2 id="延申">延申</h2>
<h3 id="容器编排">容器编排</h3>
<p>面临一组容器配合使用的情况,例如一个包括负载均衡——网站后台——数据库的 Web 系统,我们可以使用 Docker 提供的 <a href="https://github.com/docker/compose" target="_blank" rel="noopener">Compose</a> 完成统一配置管理。它将提供相同功能的容器定义为服务 <code>service</code>——以方便复用;将完整的容器组合组成项目 <code>project</code> 以方便统一管理。所有的配置通过一个 yml 文件即可实现。</p>
<h3 id="nvidia-docker">Nvidia Docker</h3>
<p>对使用 GPU 的容器,Docker 提供 <a href="https://github.com/NVIDIA/nvidia-docker" target="_blank" rel="noopener">Nvidia Docker</a> 以发挥 GPU 的运算性能。</p>
<p>基本要求如下:</p>
<ul>
<li>GNU/Linux x86_64 with kernel version &gt; 3.10</li>
<li>Docker &gt;= 1.12</li>
<li>NVIDIA GPU with Architecture &gt; Fermi (2.1)</li>
<li>NVIDIA drivers ~= 361.93 (untested on older versions)</li>
</ul>
<p>详细安装使用见 <a href="https://github.com/NVIDIA/nvidia-docker/wiki/Installation-%28version-2.0%29" target="_blank" rel="noopener">官方项目 Wiki</a></p>
</description>
</item>
<item>
<title>Docker -02- 进阶生态</title>
<link>https://szthanatos.github.io/series/docker/ecology/</link>
<pubDate>Thu, 06 Dec 2018 10:06:06 +0800</pubDate>
<guid>https://szthanatos.github.io/series/docker/ecology/</guid>
<description></description>
</item>
<item>
<title>开启 WSL2 安装 Ubuntu</title>
<link>https://szthanatos.github.io/series/wsl2/coding_with_wsl2_01/</link>
<pubDate>Sat, 22 Aug 2020 11:37:05 +0800</pubDate>
<guid>https://szthanatos.github.io/series/wsl2/coding_with_wsl2_01/</guid>
<description><h2 id="什么是-wsl">什么是 WSL</h2>
<blockquote>
<p>适用于 Linux 的 Windows 子系统可让开发人员按原样运行 GNU/Linux 环境 - 包括大多数命令行工具、实用工具和应用程序 - 且不会产生传统虚拟机或双启动设置开销。</p>
</blockquote>
<p>然而现在出的 WSL2 是基于 Hyper-V 虚拟机的&hellip;</p>
<h2 id="什么是-wsl-2">什么是 WSL 2</h2>
<blockquote>
<p>WSL 2 是适用于 Linux 的 Windows 子系统体系结构的一个新版本,它支持适用于 Linux 的 Windows 子系统在 Windows 上运行 ELF64 Linux 二进制文件。 它的主要目标是提高文件系统性能,以及添加完全的系统调用兼容性。</p>
</blockquote>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/17/zHdkqBjmfw6sbUr.png" alt="wsl1 vs wsl2" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<p>wsl1 其实感觉速度更快,和 windows 共享网络,而且没有文件系统的限制。</p>
<p>然而 wsl1 不是完整 Linux 内核,不支持 Docker。如果你只是要一个 Linux 环境可以考虑使用 wsl1 。</p>
<h2 id="安装">安装</h2>
<h3 id="启用-windows-subsystem-linux">启用 Windows-Subsystem-Linux</h3>
<p>在 <code>控制面板</code>-<code>程序</code>- <code>启用或关闭 Windows 功能</code> 中勾选 <code>适用于 Linux 的 Windows 子系统</code> 以及 <code>虚拟机平台</code>(wsl2 需要)</p>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/17/NOw3m5flE8Fd62C.png" alt="启用 wsl2" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<p>或者通过命令行(管理员身份)执行:</p>
<pre><code class="language-powershell"># 适用于 Linux 的 Windows 子系统
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
# 虚拟机平台
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
</code></pre>
<p>完成后需要重启电脑。</p>
<h3 id="更新内核">更新内核</h3>
<p>目前版本的 Win10 需要手动更新 WSL2 内核,前往 <a href="https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi" target="_blank" rel="noopener">下载适用于 x64 计算机的最新 WSL2 Linux 内核</a> 下载 msi 文件手动更新。</p>
<p><em>ARM 平台前往 <a href="https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_arm64.msi" target="_blank" rel="noopener">下载适用于 ARM64 计算机的最新 WSL2 Linux 内核</a></em></p>
<h3 id="设置-wsl-默认版本">设置 wsl 默认版本</h3>
<p>通过命令行(管理员身份)执行:</p>
<pre><code class="language-powershell">wsl --set-default-version 2
</code></pre>
<p>让未来的 Linux 都默认以 WSL2 形式安装。</p>
<p>现有 WSL 虚拟机也可以通过:</p>
<pre><code class="language-powershell"># 获取现有 wsl 版本信息
wsl --list --verbose
# 将现有发行版转化为制定版本
wsl --set-version &lt;distribution name&gt; &lt;versionNumber&gt;
</code></pre>
<p>升级到 WSL2 。</p>
<h2 id="安装-linux-系统">安装 Linux 系统</h2>
<p>当前有两种方式可选,通过微软商城一键安装或者通过wsl命令手动安装。</p>
<h3 id="a-微软商城安装">a. 微软商城安装</h3>
<p>打开 <a href="https://aka.ms/wslstore" target="_blank" rel="noopener">Microsoft Store</a>,搜索 wsl 即可获取可用 Linux 发行版。</p>
<p>现在支持的发行版有:</p>
<ul>
<li>Ubuntu 16.04 LTS</li>
<li>Ubuntu 18.04 LTS</li>
<li>Ubuntu 20.04 LTS</li>
<li>openSUSE Leap 15.1</li>
<li>SUSE Linux Enterprise Server 12 SP5</li>
<li>SUSE Linux Enterprise Server 15 SP1</li>
<li>Kali Linux</li>
<li>Debian GNU/Linux</li>
<li>Fedora Remix for WSL</li>
<li>Pengwin</li>
<li>Pengwin Enterprise</li>
<li>Alpine WSL</li>
</ul>
<p>下载完成后,点击图标进入,首次使用会需要几分钟执行安装。</p>
<p>完成安装后,设置 Ubuntu 用户名(非 root)及密码,正式开启 Ubuntu 系统。</p>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://docs.microsoft.com/zh-cn/windows/wsl/media/ubuntuinstall.png" alt="安装" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<h3 id="b-手动安装推荐">b. 手动安装(推荐)</h3>
<p>当前 Ubuntu 官方提供多个版本的镜像:</p>
<ul>
<li>Ubuntu Desktop——桌面版,带GUI界面和常用软件,大约3G;</li>
<li>Ubuntu Server——服务器版,默认不带GUI,大约1G;</li>
<li><code>Ubuntu Cloud</code>——云版,相比服务器版更精简,大约450M;</li>
<li>Ubuntu Core——为树莓派等嵌入式设备打包的特殊版本,最轻,大约300M;</li>
</ul>
<p>这里我们选择云版镜像。</p>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/18/z5asZRPGOcJEFLj.jpg" alt="Ubuntu Cloud" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<p>前往 <a href="https://cloud-images.ubuntu.com/" target="_blank" rel="noopener">Ubuntu Cloud Images</a> 官方镜像站,
下载镜像。</p>
<p>以 <a href="http://cloud-images.ubuntu.com/focal/current/" target="_blank" rel="noopener">Ubuntu 20.10 LTS</a> 为例,
以 <code>wsl</code>为关键字,找到 AMD 或 ARM 平台对应镜像文件,下载。</p>
<p>
<figure >
<div class="d-flex justify-content-center">
<div class="w-100" ><img src="https://i.loli.net/2021/06/18/ujlh7mFHDa58AUv.jpg" alt="Ubuntu 20.10 LTS" loading="lazy" data-zoomable /></div>
</div></figure>
</p>
<p>之后通过命令</p>
<pre><code class="language-powershell">wsl --import {名称} &quot;{安装位置}&quot; &quot;{镜像位置}&quot;
</code></pre>
<p>安装系统,注意路径的双引号不要省略。</p>
<h2 id="常用操作">常用操作</h2>
<h3 id="wsl-命令">wsl 命令</h3>
<ul>
<li><code>wsl --shutdown</code> 立即终止所有正在运行的发行版和 WSL 2 轻型工具虚拟机</li>
<li><code>wsl -t &lt;发行版&gt;</code> 终止指定的发行版</li>
<li><code>wsl -l</code> 列出发行版</li>
<li><code>wsl -l -v</code> 列出发行版及其版本信息</li>
<li><code>wsl -s &lt;发行版&gt;</code> 将发行版设为默认</li>
<li><code>wsl --export &lt;发行版&gt; &lt;文件名&gt;</code> 将发行版导出到 tar 文件</li>
<li><code>wsl --import &lt;发行版&gt; &lt;安装位置&gt; &lt;文件名&gt; [选项]</code> 将指定的 tar 文件作为新发行版进行导入</li>
</ul>
<p>注意,导入导出发行版会导致无法从 Microsoft 应用管理中管理或更新。</p>
<h3 id="网络">网络</h3>
<p>WSL2 相当于独立虚拟机,而 WSL1 是和 Windows 复用同一个网络的。</p>
<p>然后和一般宿主机虚拟机略微相反,从 Windows 可以通过 <code>localhost</code> 访问 WSL 上的服务,反之则不行。</p>
<p>想要访问 Windows 上的服务,可以使用命令</p>
<pre><code class="language-bash">ip route | grep default | awk '{print $3}'
</code></pre>
<p>或者查询 <code>/etc/resolv.conf</code> 中的 <code>nameserver</code> 获取到 Windows 宿主机的 ip,</p>
<p>然后通过 ip 访问。</p>
<h3 id="文件系统">文件系统</h3>
<p>WSL1 的时候,文件目录位于</p>
<ul>
<li>Ubuntu: <code>%localappdata%\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs</code></li>
<li>Ubuntu18.04: <code>%localappdata%\Packages\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\LocalState\rootfs</code></li>
</ul>
<p>WSL2 可以直接通过 <code>\\wsl$</code> 在文件管理器中查看到网络位置上的 WSL 虚拟机,Ubuntu 就是 <code>\\wsl$\Ubuntu</code>。</p>
<p>或者你可以从 WSL2 中直接打开当前目录,直接在终端里调用 <code>explorer.exe .</code> 就行了,非常 cool~</p>
<p>Windows 的磁盘在 WSL 中都表示为 <code>/mnt/c|d|e...</code>,可以看,但是操作还是尽量拷贝到 WSL 目录下,因为性能损失巨大。</p>
<h3 id="清理磁盘空间">清理磁盘空间</h3>
<p>在 Linux 下回收文件系统上所有未使用的块:</p>
<pre><code class="language-bash">sudo fstrim /
</code></pre>
<p>对于 Win10 专业版,使用如下命令压缩 WSL 虚拟机占用空间:</p>
<pre><code class="language-powershell">wsl --shutdown
optimize-vhd -Path &quot;{安装位置\ext4.vhdx}&quot; -Mode full
</code></pre>
<p>对于家庭版:</p>
<pre><code class="language-powershell">wsl --shutdown
diskpart
# 打开新的 Diskpart 窗口
select vdisk file=&quot;{安装位置\ext4.vhdx}&quot;
attach vdisk readonly
compact vdisk
detach vdisk
exit
</code></pre>
<h2 id="移动安装位置可选">移动安装位置(可选)</h2>
<p>通过商城安装的系统无法设置安装路径,使用一段时间后体积会膨胀到 10G+ ,
可以通过开源工具 <a href="https://github.com/DDoSolitary/LxRunOffline" target="_blank" rel="noopener">LxRunOffline</a>
实现将 Linux 安装到任意位置,或者将现有 Linux 子系统移动到任意位置。</p>
<p>如果是命令行安装,直接 <code>wsl --export</code>, <code>wsl --import</code> 就好。</p>
<h3 id="安装-lxrunoffline">安装 LxRunOffline</h3>
<p><a href="https://scoop.sh/" target="_blank" rel="noopener">Scoop</a> 是一个 Window 命令行包管理器,可以提供类似 apt/yum 的体验。</p>
<p>通过 Scoop 安装 LxRunOffline 方法如下:</p>
<pre><code class="language-powershell"># 在 Powershell 中执行
set-executionpolicy remotesigned -scope currentuser
iex (new-object net.webclient).downloadstring('https://get.scoop.sh')
scoop bucket add extras
scoop install lxrunoffline
</code></pre>
<p>或者你可以直接下载安装二进制文件,之后运行 <code>regsvr32 LxRunOfflineShellExt.dll</code> 完成。</p>
<h3 id="移动">移动</h3>
<pre><code class="language-powershell"># 在 Powershell 中执行
# 查看所有已安装的发行版
lxrunoffline gd
# 移动已存在发行版, 路径格式类似于 D:\wsl\Ubuntu-18.04
LxRunOffline m -n &lt;发行版名称&gt; -d &lt; 路径 &gt;
# 等待一段时间完成移动,查看发行版当前位置
LxRunOffline di -n &lt;发行版名称&gt;
</code></pre>
<h2 id="gpu">GPU</h2>
<p>差不多能用:</p>
<ul>
<li><a href="https://docs.microsoft.com/en-us/windows/win32/direct3d12/gpu-cuda-in-wsl" target="_blank" rel="noopener">在 WSL 2 中启用 NVIDIA CUDA</a></li>
<li><a href="https://developer.nvidia.com/cuda/wsl" target="_blank" rel="noopener">CUDA on Windows Subsystem for Linux (WSL) - Public Preview</a></li>
</ul>
<h2 id="参考文档">参考文档</h2>
<ul>
<li><a href="https://docs.microsoft.com/zh-cn/windows/wsl/" target="_blank" rel="noopener">WSL 文档</a></li>
<li><a href="https://docs.microsoft.com/zh-cn/windows/wsl/wsl2-faq" target="_blank" rel="noopener">WSL 2 常见问题解答</a></li>
</ul>
</description>
</item>
<item>
<title>Kafka -01- 安装配置</title>
<link>https://szthanatos.github.io/series/kafka/install/</link>
<pubDate>Thu, 06 Dec 2018 10:09:46 +0800</pubDate>
<guid>https://szthanatos.github.io/series/kafka/install/</guid>
<description><h2 id="环境说明">环境说明</h2>
<table>
<thead>
<tr>
<th>当前版本</th>
<th>发布日期</th>
<th>下载地址</th>
</tr>
</thead>
<tbody>
<tr>
<td>2.0</td>
<td>2018-07-30</td>
<td><a href="https://www.apache.org/dyn/closer.cgi?path=/kafka/2.0.0/kafka_2.11-2.0.0.tgz" target="_blank" rel="noopener">官方 2.0.0 镜像</a></td>
</tr>
</tbody>
</table>
<h2 id="安装步骤">安装步骤</h2>
<p>_** 注意:** 文中以 <code>{}</code> 包裹起来的内容需要自己替换,并非直接使用_</p>
<h3 id="0-环境准备">0. 环境准备</h3>
<table>
<thead>
<tr>
<th>基础环境</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Java</strong></td>
<td>Java 版本应该在 8(jdk1.8) 或以上,以更好的支持 G1 回收</td>
</tr>
<tr>
<td><strong>硬件参数</strong></td>
<td>CPU: 英特尔至强 E5-2650 v4 <em>2 (共计 24 核) <br>Mem: DDR4 内存 - 32GB</em> 8 <br>Sto: 2000GB * 8 raid 0</td>
</tr>
<tr>
<td><strong>文件路径</strong></td>
<td>/home/tools/kafka_2.11-2.0.0/</td>
</tr>
<tr>
<td><strong>数据存放位置</strong></td>
<td>/home/sdb/kafka-logs,/home/sdc/kafka-logs, <br>/home/sdd/kafka-logs,/home/sde/kafka-logs, <br>/home/sdf/kafka-logs,/home/sdg/kafka-logs, <br>/home/sdh/kafka-logs,/home/sdi/kafka-logs</td>
</tr>
<tr>
<td><strong>zookeeper 集群位置</strong></td>
<td>10.10.20.83:2181,10.10.20.84:2181,10.10.20.85:2181</td>
</tr>
</tbody>
</table>
<h3 id="1-下载安装">1. 下载安装</h3>
<p>下载最新版本 Kafka,解压到指定目录,无需其他操作即完成安装。</p>
<pre><code class="language-bash">tar -xzf kafka_2.11-2.0.0.tgz -C /home/tools
cd kafka_2.11-2.0.0
</code></pre>
<h3 id="2-配置集群参数">2. 配置集群参数</h3>
<p>修改 <code>config/server.properties</code></p>
<p>基本参数如下:</p>
<pre><code class="language-bash"># broker 唯一 id,值为不重复正整数
broker.id={n: int}
# 服务监听地址
listeners=PLAINTEXT://{your.host}:9092
# 日志存放位置列表,以逗号隔开
log.dirs={data.storage.list}
# zookeeper 地址列表,以逗号隔开
zookeeper.connect={zookeeper.server.list}
</code></pre>
<p>优化参数配置如下:</p>
<pre><code class="language-bash"># 消息处理线程数,建议数量为 cpu 核数加 1
num.network.threads=25
# 磁盘 IO 的线程数, 建议为 cpu 核数 2 倍,最大不超过 3 倍
num.io.threads=48
# 拉取线程数,影响 follower 的 I/O 并发度,单位时间内 leader 持有更多请求,相应负载会增大
num.replica.fetchers=2
# 分区数量配置,根据业务情况修改
num.partitions=16
# 消息日志备份数,默认是 1
default.replication.factor=2
# 刷盘 (写入文件到磁盘) 间隔消息数,建议设为 10000
log.flush.interval.messages=10000
# 刷盘间隔毫秒数,建议 1 秒 (1000)
log.flush.interval.ms=1000
# 日志保留小时数
log.retention.hours=48
# 段文件大小,过小会产生很多小文件降低性能,过大会影响快速回收磁盘空间以及 Kafka 重启后的载入速度
og.segment.bytes=1073741824
# 最大字节数,默认 1M,可以调到 5M 以上
replica.fetch.max.bytes=5242880
# 可接受数据大小,受限于 java int 类型的取值范围, 超出后会报 OOM 异常
socket.request.max.bytes=2147483600