-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
538 lines (333 loc) · 199 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
536
537
538
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Blog</title>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2018-12-13T07:58:55.856Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>Zheng Benwu</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>线上TIME_WAIT日志记录总结</title>
<link href="http://yoursite.com/2018/12/13/%E7%BA%BF%E4%B8%8ATIME-WAIT%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95%E6%80%BB%E7%BB%93/"/>
<id>http://yoursite.com/2018/12/13/线上TIME-WAIT日志记录总结/</id>
<published>2018-12-13T07:55:57.000Z</published>
<updated>2018-12-13T07:58:55.856Z</updated>
<content type="html"><![CDATA[<p>首先发现的是平响太高了,之后又降下来了。然后,开始查询原因。下面是过程记录</p><p>刚开始是追寻的问题是: CLB的“心跳”突然没了?(注:CLB是负载均衡,心跳应该是CLB那边用来检测的。是一个文件。)<br><a id="more"></a><br>查看php-fpm数量,发现有434个;最后群里有人说是他调的<br><img src="/uploads/2018/12/network_timewait_001.jpg" alt=""><br><img src="/uploads/2018/12/network_timewait_002.png" alt=""></p><p>然后就开始查询为啥“心跳”没了。<br>回答:CLB改心跳检查接口的话,如果改动比较大,应该是大面积报。最后问题回归到我们这边。</p><p>回答为啥将PHP-FPM数量调高?<br>我理解是这样的,后端有请求时间过长的接口,然后PHP-FPM都用于处理了这些请求长的接口,然后堵住了,然后导致后边的请求都在等待,包括心跳的。<br>心跳5s超时,前端CLB自己断的连接,报的499.<br><img src="/uploads/2018/12/network_timewait_003.png" alt=""><br>所以,增加了fpm的进程数。</p><p>查看PHP的error。 只报进程数不够。突然频繁启动PHP进程,结果达到最大值了。<br><img src="/uploads/2018/12/network_timewait_004.jpg" alt=""></p><p><em>说明:在这个时间点,服务器内存和CPU也都没有问题。</em></p><p>在监控记录中发现,5xx的记录有一个高峰。如下图:<br><img src="/uploads/2018/12/network_timewait_005.jpg" alt=""><br>并且,报这么多错误,项目日志中并没有记录。(说明不是项目导致的问题)</p><p>然后有人在监控记录中有了新发现,如下图:<br><img src="/uploads/2018/12/network_timewait_006.jpg" alt=""><br><img src="/uploads/2018/12/network_timewait_007.jpg" alt=""></p><p><em>注:在双十一期间,机器是10台。双十一前是2台(并且量不高)。双十一之后恢复到2台(量比以前高了点)。</em></p><p>现在确定原因了,由于双十一之后量比以前增多了,导致 timewait 增多,2台机器的端口不能够满足那么大的连接。导致频频报5xx。</p><p><strong>解决方案:</strong><br>服务器降级,多开几台低配,降低 timewait。(注:timewait不可避免,只能通过增加机器,或者是调整服务端配置,提高timewait的回收速度。)</p>]]></content>
<summary type="html">
<p>首先发现的是平响太高了,之后又降下来了。然后,开始查询原因。下面是过程记录</p>
<p>刚开始是追寻的问题是: CLB的“心跳”突然没了?(注:CLB是负载均衡,心跳应该是CLB那边用来检测的。是一个文件。)<br>
</summary>
<category term="问题" scheme="http://yoursite.com/categories/%E9%97%AE%E9%A2%98/"/>
<category term="线上业务" scheme="http://yoursite.com/categories/%E9%97%AE%E9%A2%98/%E7%BA%BF%E4%B8%8A%E4%B8%9A%E5%8A%A1/"/>
<category term="问题" scheme="http://yoursite.com/tags/%E9%97%AE%E9%A2%98/"/>
</entry>
<entry>
<title>HTTP之长连接、短连接</title>
<link href="http://yoursite.com/2018/12/11/HTTP%E4%B9%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%E3%80%81%E7%9F%AD%E8%BF%9E%E6%8E%A5/"/>
<id>http://yoursite.com/2018/12/11/HTTP之长连接、短连接/</id>
<published>2018-12-11T03:58:29.000Z</published>
<updated>2018-12-11T04:33:36.561Z</updated>
<content type="html"><![CDATA[<h4 id="1、什么是长连接、短连接?"><a href="#1、什么是长连接、短连接?" class="headerlink" title="1、什么是长连接、短连接?"></a>1、什么是长连接、短连接?</h4><p>在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。</p><p>而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:<code>Connection:keep-alive</code>。<br><a id="more"></a><br>在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。</p><p>HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。</p><h4 id="2、TCP连接"><a href="#2、TCP连接" class="headerlink" title="2、TCP连接"></a>2、TCP连接</h4><p>当网络通信时采用TCP协议时,在真正的读写操作之前,客户端与服务器端之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时可以释放这个连接。连接的建立依靠“三次握手”,而释放则需要“四次握手”,所以每个连接的建立都是需要资源消耗和时间消耗的。<br>经典的三次握手建立连接示意图:<br><img src="/uploads/2018/12/network_tcp_01.jpg" alt=""><br><img src="/uploads/2018/12/network_tcp_02.png" alt=""><br>经典的四次握手关闭连接示意图:<br><img src="/uploads/2018/12/network_tcp_03.jpg" alt=""><br><img src="/uploads/2018/12/network_tcp_04.jpg" alt=""></p><h5 id="(1)TCP短连接"><a href="#(1)TCP短连接" class="headerlink" title="(1)TCP短连接"></a>(1)TCP短连接</h5><p>模拟一下TCP短连接的情况:client向server发起连接请求,server接到请求,然后双方建立连接。client向server发送消息,server回应client,然后一次请求就完成了。这时候双方任意都可以发起close操作,不过一般都是client先发起close操作。上述可知,短连接一般只会在 client/server间传递一次请求操作。</p><p>短连接的优点是:管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段。</p><h5 id="(2)TCP长连接"><a href="#(2)TCP长连接" class="headerlink" title="(2)TCP长连接"></a>(2)TCP长连接</h5><p>我们再模拟一下长连接的情况:client向server发起连接,server接受client连接,双方建立连接,client与server完成一次请求后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。</p><p>TCP的保活功能主要为服务器应用提供。如果客户端已经消失而连接未断开,则会使得服务器上保留一个半开放的连接,而服务器又在等待来自客户端的数据,此时服务器将永远等待客户端的数据。保活功能就是试图在服务端器端检测到这种半开放的连接。</p><p>如果一个给定的连接在两小时内没有任何动作,服务器就向客户发送一个探测报文段,根据客户端主机响应探测4个客户端状态:</p><ul><li>客户主机依然正常运行,且服务器可达。此时客户的TCP响应正常,服务器将保活定时器复位。</li><li>客户主机已经崩溃,并且关闭或者正在重新启动。上述情况下客户端都不能响应TCP。服务端将无法收到客户端对探测的响应。服务器总共发送10个这样的探测,每个间隔75秒。若服务器没有收到任何一个响应,它就认为客户端已经关闭并终止连接。</li><li>客户端崩溃并已经重新启动。服务器将收到一个对其保活探测的响应,这个响应是一个复位,使得服务器终止这个连接。</li><li>客户机正常运行,但是服务器不可达。这种情况与第二种状态类似。</li></ul><blockquote><p>易混淆概念:TCP的keep alive和HTTP的Keep-alive<br>TCP的keep alive是检查当前TCP连接是否活着;HTTP的Keep-alive是要让一个TCP连接活久点。它们是不同层次的概念。</p><blockquote><p>TCP keep alive的表现:<br>当一个连接“一段时间”没有数据通讯时,一方会发出一个心跳包(Keep Alive包),如果对方有回包则表明当前连接有效,继续监控。</p></blockquote></blockquote><blockquote><p>HTTP的Keep-alive<br>(1)HTTP Keep-Alive<br>在http早期,每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。<br>使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。<br>但是,keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep-alive,有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout时间非常重要。<br>(2)keepalvie timeout<br>Httpd守护进程,一般都提供了keep-alive timeout时间设置参数。比如nginx的keepalive_timeout,和Apache的KeepAliveTimeout。这个keepalive_timout时间值意味着:一个http产生的tcp连接在传送完最后一个响应后,还需要hold住keepalive_timeout秒后,才开始关闭这个连接。<br>当httpd守护进程发送完一个响应后,理应马上主动关闭相应的tcp连接,设置 keepalive_timeout后,httpd守护进程会想说:”再等等吧,看看浏览器还有没有请求过来”,这一等,便是keepalive_timeout时间。如果守护进程在这个等待的时间里,一直没有收到浏览发过来http请求,则关闭这个http连接。</p></blockquote><h4 id="3、长短连接的优缺点:"><a href="#3、长短连接的优缺点:" class="headerlink" title="3、长短连接的优缺点:"></a>3、长短连接的优缺点:</h4><p>长连接和短连接的产生在于client和server采取的关闭策略。不同的应用场景适合采用不同的策略。</p><p>由上可以看出,长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,较适用长连接。不过这里存在一个问题,存活功能的探测周期太长,还有就是它只是探测TCP连接的存活,属于比较斯文的做法,遇到恶意的连接时,保活功能就不够使了。在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可 以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。</p><p>短连接对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如果客户请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽</p><h4 id="4、长短连接操作过程:"><a href="#4、长短连接操作过程:" class="headerlink" title="4、长短连接操作过程:"></a>4、长短连接操作过程:</h4><ul><li>短连接:<br>操作步骤:连接->传输数据->关闭连接</li><li>长连接:<br>操作步骤:连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。</li></ul><h4 id="5、什么时候用长连接,短连接?"><a href="#5、什么时候用长连接,短连接?" class="headerlink" title="5、什么时候用长连接,短连接? "></a>5、什么时候用长连接,短连接? </h4><p>长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。 </p><p>而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。</p><p>参考文章:<br>HTTP长连接、短连接究竟是什么?:<a href="https://www.cnblogs.com/gotodsp/p/6366163.html" target="_blank" rel="noopener">https://www.cnblogs.com/gotodsp/p/6366163.html</a><br>HTTP 的长连接和短连接:<a href="http://blog.jobbole.com/104108/" target="_blank" rel="noopener">http://blog.jobbole.com/104108/</a><br>http keep_alive 和 tcp keep_alive:<a href="https://blog.csdn.net/lys86_1205/article/details/21234867" target="_blank" rel="noopener">https://blog.csdn.net/lys86_1205/article/details/21234867</a><br>HTTP Keep-Alive模式:<a href="http://www.cnblogs.com/skynet/archive/2010/12/11/1903347.html" target="_blank" rel="noopener">http://www.cnblogs.com/skynet/archive/2010/12/11/1903347.html</a></p>]]></content>
<summary type="html">
<h4 id="1、什么是长连接、短连接?"><a href="#1、什么是长连接、短连接?" class="headerlink" title="1、什么是长连接、短连接?"></a>1、什么是长连接、短连接?</h4><p>在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。</p>
<p>而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:<code>Connection:keep-alive</code>。<br>
</summary>
<category term="计算机网络" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
<category term="计算机网络" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
<category term="HTTP" scheme="http://yoursite.com/tags/HTTP/"/>
</entry>
<entry>
<title>HTTP之TIME_WAIT解析</title>
<link href="http://yoursite.com/2018/12/11/HTTP%E4%B9%8BTIME-WAIT%E8%A7%A3%E6%9E%90/"/>
<id>http://yoursite.com/2018/12/11/HTTP之TIME-WAIT解析/</id>
<published>2018-12-11T03:58:23.000Z</published>
<updated>2018-12-11T04:32:39.956Z</updated>
<content type="html"><![CDATA[<h4 id="1、查看服务器连接状态信息"><a href="#1、查看服务器连接状态信息" class="headerlink" title="1、查看服务器连接状态信息"></a>1、查看服务器连接状态信息</h4><p>查看服务器TCP链接状态信息:<br><code>netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'</code></p><p>它会显示例如下面的信息:<br>TIME_WAIT 814<br>CLOSE_WAIT 1<br>FIN_WAIT1 1<br>ESTABLISHED 634<br>SYN_RECV 2<br>LAST_ACK 1</p><p>常用的三个状态是:ESTABLISHED 表示正在通信(表示正常数据传输状态),TIME_WAIT 表示主动关闭(表示处理完毕,等待超时结束的请求数),CLOSE_WAIT 表示被动关闭。<br><a id="more"></a><br>具体每种状态什么意思,看下图就明白了:<br><img src="/uploads/2018/12/network_timewait_00.gif" alt=""></p><p>这么多状态不用都记住,只要了解到我上面提到的最常见的三种状态的意义就可以了。一般不到万不得已的情况也不会去查看网络状态,如果服务器出了异常,百分之八九十都是下面两种情况:</p><ol><li>服务器保持了大量TIME_WAIT状态</li><li>服务器保持了大量CLOSE_WAIT状态</li></ol><p>因为linux分配给一个用户的文件句柄是有限的,而TIME_WAIT和CLOSE_WAIT两种状态如果一直被保持,那么意味着对应数目的通道就一直被占着,而且是“占着茅坑不使劲”,一旦达到句柄数上限,新的请求就无法被处理了,接着就是大量Too Many Open Files异常,tomcat崩溃。。。</p><h4 id="2、文件句柄说明"><a href="#2、文件句柄说明" class="headerlink" title="2、文件句柄说明"></a>2、文件句柄说明</h4><p>在Linux里头“一切皆文件”,提示“Too Many Open Files异常”表示句柄不够用了。对应可能就是socket或设备打开太多导致的。</p><p>linux在文件句柄的数目上有两个级别的限制。一个是系统级别的总数限制,一个是针对用户的限制。</p><h5 id="(1)系统级别的句柄操作"><a href="#(1)系统级别的句柄操作" class="headerlink" title="(1)系统级别的句柄操作"></a>(1)系统级别的句柄操作</h5><ul><li>查看系统的句柄限制:<br><code>sysctl -a | grep fs.file-max</code><br>或者<br><code>cat /proc/sys/fs/file-max</code></li><li>修改句柄数限制:<br><code>sysctl -w fs.file-max 797692</code><br>或者<br><code>echo "797692" > /proc/sys/fs/file-max</code><br>两者作用是相同的,前者改内核参数,后者直接作用于内核参数在虚拟文件系统(procfs,psuedo file system)上对应的文件而已。<br>或者<br>修改内核参数 /etc/sysctl.conf<br><code>echo "fs.file-max=797692" >> /etc/sysctl.conf</code><br>(注:查看内核参数: sysctl -p)<br>*查看整个系统目前使用的文件句柄数量命令:<br><code>cat /proc/sys/fs/file-nr</code></li></ul><h5 id="(2)用户级别的句柄操作"><a href="#(2)用户级别的句柄操作" class="headerlink" title="(2)用户级别的句柄操作"></a>(2)用户级别的句柄操作</h5><ul><li>查看当前用户的文件句柄限制: ulimit -a</li><li>修改句柄数限制:<br>修改 /etc/security/limits.conf 增加下面代码:<figure class="highlight plain"><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">* soft nofile 262140</span><br><span class="line">* hard nofile 262140</span><br><span class="line">* soft nproc 102400</span><br><span class="line">* hard nproc 102400</span><br></pre></td></tr></table></figure></li></ul><p>(注:*标识所有用户)<br>有两种限制,一种是soft软限制,在数目超过软限制的时候系统会给出warning警告,但是达到hard硬限制的时候系统将拒绝或者异常了。<br>(注:修改之后可能需要重启shell生效。)</p><h5 id="(3)其它操作"><a href="#(3)其它操作" class="headerlink" title="(3)其它操作"></a>(3)其它操作</h5><p>查看某个进程开了那些句柄: <code>lsof -p pid</code><br>某个进程开了几个句柄: <code>lsof -p pid | wc -l</code><br>可以看到某个目录/文件被什么进程占用了,显示已打开该目录或文件的所有进程信息: <code>lsof path/filename</code></p><h4 id="3、下面来讨论下这两种情况的处理方法:"><a href="#3、下面来讨论下这两种情况的处理方法:" class="headerlink" title="3、下面来讨论下这两种情况的处理方法:"></a>3、下面来讨论下这两种情况的处理方法:</h4><h5 id="(1)服务器保持了大量TIME-WAIT状态"><a href="#(1)服务器保持了大量TIME-WAIT状态" class="headerlink" title="(1)服务器保持了大量TIME_WAIT状态"></a>(1)服务器保持了大量TIME_WAIT状态</h5><p>这种情况比较常见,一些爬虫服务器或者WEB服务器(如果网管在安装的时候没有做内核参数优化的话)上经常会遇到这个问题,这个问题是怎么产生的呢?</p><p>从 上面的示意图可以看得出来,TIME_WAIT是主动关闭连接的一方保持的状态,对于爬虫服务器来说他本身就是“客户端”,在完成一个爬取任务之后,他就 会发起主动关闭连接,从而进入TIME_WAIT的状态,然后在保持这个状态2MSL(max segment lifetime)时间之后,彻底关闭回收资源。为什么要这么做?明明就已经主动关闭连接了为啥还要保持资源一段时间呢?这个是TCP/IP的设计者规定 的,主要出于以下两个方面的考虑:</p><ol><li>防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)</li><li>可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。</li></ol><blockquote><p>关于MSL引用下面一段话:<br>MSL为一个TCP Segment(某一块TCP网路封包)从来源送到目的之间可续存的时间(也就是一个网路封包再网路上传输时能存活的时间),由于RFC 793 TCP传输协议是在1981年定义的,当时的网路速度不像现在的网路那样发达,你可以想象你从浏览器输入等到第一个byte出现要等4分钟吗?在现在的网路环境下几乎不可能有这种事情发生,因此我们大可将 TIME_WAIT 状态的续存时间大幅调低,好让连接口能更快空出来给其它连线使用。</p></blockquote><blockquote><p>再引用网络资源的一段话:<br>值 得一说的是,对于基于TCP的HTTP协议,关闭TCP连接的是Server端,这样,Server端会进入TIME_WAIT状态,可 想而知,对于访 问量大的Web Server,会存在大量的TIME_WAIT状态,假如server一秒钟接收1000个请求,那么就会积压 240*1000=240,000个 TIME_WAIT的记录,维护这些状态给Server带来负担。当然现代操作系统都会用快速的查找算法来管理这些 TIME_WAIT,所以对于新的 TCP连接请求,判断是否hit中一个TIME_WAIT不会太费时间,但是有这么多状态要维护总是不好。<br>HTTP协议1.1版规定default行为是Keep-Alive,也就是会重用TCP连接传输多个 request/response,一个主要原因就是发现了这个问题</p></blockquote><p>也就是说HTTP的交互跟上面画的那个图是不一样的,关闭连接的不是客户端,而是服务器,所以web服务器也是会出现大量的TIME_WAIT的情况的。这也说清楚了,为什么我的客户端服务器会出现大量CLOSE_WAIT的情况。</p><p>现在来说如何来解决这个问题。<br>解决思路很简单,就是让服务器能够快速回收和重用那些TIME_WAIT的资源。<br>下面来看一下我们对/etc/sysctl.conf文件的修改:<br><figure class="highlight plain"><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">#对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃,不应该大于255,默认值是5,对应于180秒左右时间 </span><br><span class="line">net.ipv4.tcp_syn_retries=2 </span><br><span class="line">#net.ipv4.tcp_synack_retries=2 </span><br><span class="line">#表示当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时,改为300秒 </span><br><span class="line">net.ipv4.tcp_keepalive_time=1200 </span><br><span class="line">net.ipv4.tcp_orphan_retries=3 </span><br><span class="line">#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间 </span><br><span class="line">net.ipv4.tcp_fin_timeout=30 </span><br><span class="line">#表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。 </span><br><span class="line">net.ipv4.tcp_max_syn_backlog = 4096 </span><br><span class="line">#表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭 </span><br><span class="line">net.ipv4.tcp_syncookies = 1 </span><br><span class="line"> </span><br><span class="line">#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭 </span><br><span class="line">net.ipv4.tcp_tw_reuse = 1 </span><br><span class="line">#表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭 </span><br><span class="line">net.ipv4.tcp_tw_recycle = 1 </span><br><span class="line"> </span><br><span class="line">##减少超时前的探测次数 </span><br><span class="line">net.ipv4.tcp_keepalive_probes=5 </span><br><span class="line">##优化网络设备接收队列 </span><br><span class="line">net.core.netdev_max_backlog=3000</span><br></pre></td></tr></table></figure></p><p>修改完之后执行/sbin/sysctl -p让参数生效。</p><p>这里头主要注意到的是<br><figure class="highlight plain"><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">net.ipv4.tcp_tw_reuse </span><br><span class="line">net.ipv4.tcp_tw_recycle </span><br><span class="line">net.ipv4.tcp_fin_timeout </span><br><span class="line">net.ipv4.tcp_keepalive_*</span><br></pre></td></tr></table></figure></p><p>这几个参数。</p><blockquote><p>net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle的开启都是为了回收处于TIME_WAIT状态的资源。<br>net.ipv4.tcp_fin_timeout这个时间可以减少在异常情况下服务器从FIN-WAIT-2转到TIME_WAIT的时间。<br>net.ipv4.tcp_keepalive_*一系列参数,是用来设置服务器检测连接存活的相关配置。</p></blockquote><h5 id="(2)服务器保持了大量CLOSE-WAIT状态"><a href="#(2)服务器保持了大量CLOSE-WAIT状态" class="headerlink" title="(2)服务器保持了大量CLOSE_WAIT状态"></a>(2)服务器保持了大量CLOSE_WAIT状态</h5><p>TIME_WAIT状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的。</p><p>但是CLOSE_WAIT就不一样了,从上面的图可以看出来,如果一直保持在CLOSE_WAIT状态,那么只有一种情况,就是在对方关闭连接之后服务器程序自己没有进一步发出ack信号。换句话说,就是在对方连接关闭之后,程序里没有检测到,或者程序压根就忘记了这个时候需要关闭连接,于是这个资源就一直被程序占着。个人觉得这种情况,通过服务器内核参数也没办法解决,服务器对于程序抢占的资源没有主动回收的权利,除非终止程序运行。</p><p>简单来说CLOSE_WAIT数目过大是由于被动关闭连接处理不当导致的。</p><blockquote><p>我说一个场景,服务器A会去请求服务器B上面的apache获取文件资源,正常情况下,如果请求成功,那么在抓取完资源后服务器A会主动发出关闭连接的请求,这个时候就是主动关闭连接,连接状态我们可以看到是TIME_WAIT。如果一旦发生异常呢?假设请求的资源服务器B上并不存在,那么这个时候就会由服务器B发出关闭连接的请求,服务器A就是被动的关闭了连接,如果服务器A被动关闭连接之后自己并没有释放连接,那就会造成CLOSE_WAIT的状态了。</p></blockquote><p>所以很明显,问题还是处在程序里头。</p><p>参考资料:<br>服务器TIME_WAIT和CLOSE_WAIT详解和解决办法:<a href="https://www.cnblogs.com/sunxucool/p/3449068.html" target="_blank" rel="noopener">https://www.cnblogs.com/sunxucool/p/3449068.html</a><br>HttpClient4 TIME_WAIT和CLOSE_WAIT:<a href="https://www.cnblogs.com/caoyusongnet/p/9087633.html" target="_blank" rel="noopener">https://www.cnblogs.com/caoyusongnet/p/9087633.html</a></p>]]></content>
<summary type="html">
<h4 id="1、查看服务器连接状态信息"><a href="#1、查看服务器连接状态信息" class="headerlink" title="1、查看服务器连接状态信息"></a>1、查看服务器连接状态信息</h4><p>查看服务器TCP链接状态信息:<br><code>netstat -n | awk &#39;/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}&#39;</code></p>
<p>它会显示例如下面的信息:<br>TIME_WAIT 814<br>CLOSE_WAIT 1<br>FIN_WAIT1 1<br>ESTABLISHED 634<br>SYN_RECV 2<br>LAST_ACK 1</p>
<p>常用的三个状态是:ESTABLISHED 表示正在通信(表示正常数据传输状态),TIME_WAIT 表示主动关闭(表示处理完毕,等待超时结束的请求数),CLOSE_WAIT 表示被动关闭。<br>
</summary>
<category term="计算机网络" scheme="http://yoursite.com/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
<category term="计算机网络" scheme="http://yoursite.com/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"/>
<category term="HTTP" scheme="http://yoursite.com/tags/HTTP/"/>
</entry>
<entry>
<title>Linux命令之uniq</title>
<link href="http://yoursite.com/2018/11/20/Linux%E5%91%BD%E4%BB%A4%E4%B9%8Buniq/"/>
<id>http://yoursite.com/2018/11/20/Linux命令之uniq/</id>
<published>2018-11-20T09:21:20.000Z</published>
<updated>2018-11-20T09:40:43.238Z</updated>
<content type="html"><![CDATA[<p>uniq - 检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。<br><figure class="highlight plain"><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><br><span class="line"> uniq [-cdu][-f<栏位>][-s<字符位置>][-w<字符位置>][--help][--version][输入文件][输出文件]</span><br><span class="line">参数:</span><br><span class="line"> -c或--count 在每列旁边显示该行重复出现的次数。</span><br><span class="line"> -d或--repeated 仅显示重复出现的行列。</span><br><span class="line"> -f<栏位>或--skip-fields=<栏位> 忽略比较指定的栏位。</span><br><span class="line"> -s<字符位置>或--skip-chars=<字符位置> 忽略比较指定的字符。</span><br><span class="line"> -u或--unique 仅显示出一次的行列。</span><br><span class="line"> -w<字符位置>或--check-chars=<字符位置> 指定要比较的字符。</span><br><span class="line"> --help 显示帮助。</span><br><span class="line"> --version 显示版本信息。</span><br><span class="line"> [输入文件] 指定已排序好的文本文件。如果不指定此项,则从标准读取数据;</span><br><span class="line"> [输出文件] 指定输出的文件。如果不指定此选项,则将内容显示到标准输出设备(显示终端)。</span><br></pre></td></tr></table></figure></p><a id="more"></a><p><strong>描述:</strong></p><ul><li>uniq 命令删除文件中的重复行。</li><li>uniq 命令读取由 InFile 参数指定的标准输入或文件。该命令首先比较相邻的行,然后除去第二行和该行的后续副本。重复的行一定相邻。(在发出 uniq 命令之前,请使用 sort 命令使所有重复行相邻。)</li></ul><p><strong>实例:</strong><br>testfile中的原有内容为:<br><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">$ cat testfile #原有内容 </span><br><span class="line">test 30 </span><br><span class="line">test 30 </span><br><span class="line">test 30 </span><br><span class="line">Hello 95 </span><br><span class="line">Hello 95 </span><br><span class="line">Hello 95 </span><br><span class="line">Hello 95 </span><br><span class="line">Linux 85 </span><br><span class="line">Linux 85</span><br></pre></td></tr></table></figure></p><p>使用uniq 命令删除重复的行后,有如下输出结果:<br><figure class="highlight plain"><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">$ uniq testfile #删除重复行后的内容 </span><br><span class="line">test 30 </span><br><span class="line">Hello 95 </span><br><span class="line">Linux 85</span><br></pre></td></tr></table></figure></p><p>检查文件并删除文件中重复出现的行,并在行首显示该行重复出现的次数。使用如下命令:<br><figure class="highlight plain"><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">$ uniq -c testfile #删除重复行后的内容 </span><br><span class="line">3 test 30 #前面的数字的意义为该行共出现了3次 </span><br><span class="line">4 Hello 95 #前面的数字的意义为该行共出现了4次 </span><br><span class="line">2 Linux 85 #前面的数字的意义为该行共出现了2次</span><br></pre></td></tr></table></figure></p><font color="red">(当重复的行并不相邻时,uniq 命令是不起作用的,即若文件内容为以下时,uniq 命令不起作用。必须辅以sort排序后再过滤。)</font>]]></content>
<summary type="html">
<p>uniq - 检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。<br><figure class="highlight plain"><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><br><span class="line"> uniq [-cdu][-f&lt;栏位&gt;][-s&lt;字符位置&gt;][-w&lt;字符位置&gt;][--help][--version][输入文件][输出文件]</span><br><span class="line">参数:</span><br><span class="line"> -c或--count 在每列旁边显示该行重复出现的次数。</span><br><span class="line"> -d或--repeated 仅显示重复出现的行列。</span><br><span class="line"> -f&lt;栏位&gt;或--skip-fields=&lt;栏位&gt; 忽略比较指定的栏位。</span><br><span class="line"> -s&lt;字符位置&gt;或--skip-chars=&lt;字符位置&gt; 忽略比较指定的字符。</span><br><span class="line"> -u或--unique 仅显示出一次的行列。</span><br><span class="line"> -w&lt;字符位置&gt;或--check-chars=&lt;字符位置&gt; 指定要比较的字符。</span><br><span class="line"> --help 显示帮助。</span><br><span class="line"> --version 显示版本信息。</span><br><span class="line"> [输入文件] 指定已排序好的文本文件。如果不指定此项,则从标准读取数据;</span><br><span class="line"> [输出文件] 指定输出的文件。如果不指定此选项,则将内容显示到标准输出设备(显示终端)。</span><br></pre></td></tr></table></figure></p>
</summary>
<category term="Linux" scheme="http://yoursite.com/categories/Linux/"/>
<category term="Linux" scheme="http://yoursite.com/tags/Linux/"/>
<category term="Linux命令" scheme="http://yoursite.com/tags/Linux%E5%91%BD%E4%BB%A4/"/>
</entry>
<entry>
<title>MySQL中的SAFE UPDATE MODE</title>
<link href="http://yoursite.com/2018/11/20/MySQL%E4%B8%AD%E7%9A%84SAFE-UPDATE-MODE/"/>
<id>http://yoursite.com/2018/11/20/MySQL中的SAFE-UPDATE-MODE/</id>
<published>2018-11-20T09:20:17.000Z</published>
<updated>2018-11-20T09:25:30.761Z</updated>
<content type="html"><![CDATA[<p>写在前面:此<code>SET SQL_SAFE_UPDATES=1</code>命令可防止代码无WHERE条件更新或删除操作。</p><p>在业务中发现一个问题,报错如下:<br><img src="/uploads/2018/11/mysql_safe_update_mode.png" alt=""><br><a id="more"></a><br>在使用 <code>update</code> 的时候,报如上错误。 根据图示可发现是因为开启了 update safe mode,然后where条件中的字段没有索引导致的。</p><p>经过查找,确实发现,MySQL有SAFE UPDATE MODE模式,可使用SQL语句更改:<br><code>SET SQL_SAFE_UPDATES = 0;</code><br>相当于是解除SAFE MODE模式,则可以更新删除了。</p><p>sql_safe_updates参数可以限制不带where条件的update/delete语句执行失败,这个参数设置后,可以防止业务bug/漏洞导致把整个表都更新或者删除(线上发生过的案例),也可以防止DBA在线误操作更新/删除整张表。</p><blockquote><p>官方解释:<br>当sql_safe_updates设置为1时,UPDATE :要有where,并查询条件必须使用为索引字段,或者使用limit,或者两个条件同时存在,才能正常执行。DELETE:where条件中带有索引字段可删除,where中查询条件不是索引,得必须有limit。主要是防止UPDATE和DELETE 没有使用索引导致变更及删除大量数据。系统参数默认值为0</p></blockquote><font color="red">(经验证发现,并不是唯一索引才行(网上某些说法如此),只要是含有索引的就OK。)</font><p>为了防止线上业务出现以下3种情况影响线上服务的正常使用和不小心全表数据删除:</p><ol><li>没有加where条件的全表更新操作</li><li>加了where 条件字段,但是where 字段 没有走索引的表更新</li><li>全表delete 没有加where 条件 或者where 条件没有 走索引</li></ol><p><strong>建议:</strong> DBA 开启此参数限制 ,可以避免线上业务数据误删除操作,但是需要先在测试库开启,这样可以可以先在测试库上补充短缺的表索引,测试验证没问题再部署到线上库 邮件部从去年开始已经在严选电商线上运行。</p><p><strong>业务逻辑:</strong><br>业务中开启SAFE MODE的场景是,由于出现过代码中有更新操作,而没有传where条件,导致全部更新(幸运的是,由于更新数据量过大,更新超时,导致数据并没有被更新成功。否则,数据就得回滚了。)。没有传where条件是因为没有进行过滤验证导致的。所以,DB那边就开启了UPDATE SAFE MODE模式。<br>开启这个之后,线上数据库某些表中的字段没有索引,而<font color="red">代码中却使用了没有索引的字段做where条件进行更新。</font>才引发上面的错误。</p>]]></content>
<summary type="html">
<p>写在前面:此<code>SET SQL_SAFE_UPDATES=1</code>命令可防止代码无WHERE条件更新或删除操作。</p>
<p>在业务中发现一个问题,报错如下:<br><img src="/uploads/2018/11/mysql_safe_update_mode.png" alt=""><br>
</summary>
<category term="MySQL" scheme="http://yoursite.com/categories/MySQL/"/>
<category term="优化" scheme="http://yoursite.com/categories/MySQL/%E4%BC%98%E5%8C%96/"/>
<category term="MySQL优化" scheme="http://yoursite.com/tags/MySQL%E4%BC%98%E5%8C%96/"/>
<category term="MySQL" scheme="http://yoursite.com/tags/MySQL/"/>
<category term="优化" scheme="http://yoursite.com/tags/%E4%BC%98%E5%8C%96/"/>
</entry>
<entry>
<title>MySQL加锁详解</title>
<link href="http://yoursite.com/2018/11/20/MySQL%E5%8A%A0%E9%94%81%E8%AF%A6%E8%A7%A3/"/>
<id>http://yoursite.com/2018/11/20/MySQL加锁详解/</id>
<published>2018-11-20T09:19:29.000Z</published>
<updated>2018-11-20T09:26:10.549Z</updated>
<content type="html"><![CDATA[<h4 id="1-新建数据表:"><a href="#1-新建数据表:" class="headerlink" title="1. 新建数据表:"></a>1. 新建数据表:</h4><figure class="highlight plain"><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">| test | CREATE TABLE `test` (</span><br><span class="line"> `id` int(11) unsigned NOT NULL AUTO_INCREMENT,</span><br><span class="line"> `name` varchar(50) NOT NULL DEFAULT '',</span><br><span class="line"> `age` tinyint(3) NOT NULL,</span><br><span class="line"> `hobby` varchar(200) NOT NULL DEFAULT '',</span><br><span class="line"> PRIMARY KEY (`id`),</span><br><span class="line"> UNIQUE KEY `name` (`name`),</span><br><span class="line"> KEY `hobby` (`hobby`)</span><br><span class="line">) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 |</span><br></pre></td></tr></table></figure><a id="more"></a><h4 id="2-设置事物隔离级别:"><a href="#2-设置事物隔离级别:" class="headerlink" title="2. 设置事物隔离级别:"></a>2. 设置事物隔离级别:</h4><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">mysql> set tx_isolation='READ-COMMITTED';</span><br><span class="line">Query OK, 0 rows affected</span><br><span class="line"></span><br><span class="line">mysql> select @@tx_isolation;</span><br><span class="line">+-----------------+</span><br><span class="line">| @@tx_isolation |</span><br><span class="line">+-----------------+</span><br><span class="line">| READ-COMMITTED |</span><br><span class="line">+-----------------+</span><br><span class="line">1 row in set</span><br></pre></td></tr></table></figure><h4 id="3-测试索引对于锁的影响(事务级别:READ-COMMITTED,默认级别(REPEATABLE-READ))"><a href="#3-测试索引对于锁的影响(事务级别:READ-COMMITTED,默认级别(REPEATABLE-READ))" class="headerlink" title="3. 测试索引对于锁的影响(事务级别:READ-COMMITTED,默认级别(REPEATABLE-READ))"></a>3. 测试索引对于锁的影响(事务级别:READ-COMMITTED,默认级别(REPEATABLE-READ))</h4><h5 id="①-只含有一个主键"><a href="#①-只含有一个主键" class="headerlink" title="① 只含有一个主键"></a>① 只含有一个主键</h5><p><code>delete from test where id = 10;</code><br>这个毋庸置疑,锁的肯定是主键。在id = 10的记录上加上锁即可。<br><img src="/uploads/2018/11/mysql_index_00.jpg" alt=""></p><h5 id="②-只含有一个唯一键"><a href="#②-只含有一个唯一键" class="headerlink" title="② 只含有一个唯一键"></a>② 只含有一个唯一键</h5><p><code>delete from test where id = 10;</code><br>这个id不是主键,而是一个Unique的二级索引键值。<br><img src="/uploads/2018/11/mysql_index_01.jpg" alt=""><br>由于id是unique索引,因此delete语句会选择走id列的索引进行where条件的过滤,在找到id=10的记录后,首先会将unique索引上的id=10索引记录加上X锁,同时,会根据读取到的name列,回主键索引(聚簇索引),然后将聚簇索引上的name = ‘d’ 对应的主键索引项加X锁。</p><blockquote><p>为什么聚簇索引上的记录也要加锁?试想一下,如果并发的一个SQL,是通过主键索引来更新:update t1 set id = 100 where name = ‘d’; 此时,如果delete语句没有将主键索引上的记录加锁,那么并发的update就会感知不到delete语句的存在,违背了同一记录上的更新/删除需要串行执行的约束。</p></blockquote><h5 id="③-仅含有一个普通索引"><a href="#③-仅含有一个普通索引" class="headerlink" title="③ 仅含有一个普通索引"></a>③ 仅含有一个普通索引</h5><p><code>delete from test where id = 10;</code><br>相对于前两个的变化,id列上的约束又降低了,id列不再唯一,只有一个普通的索引。<br><img src="/uploads/2018/11/mysql_index_02.jpg" alt=""><br>根据此图,可以看到,首先,id列索引上,满足id = 10查询条件的记录,均已加锁。同时,这些记录对应的主键索引上的记录也都加上了锁。与②唯一的区别在于,②最多只有一个满足等值查询的记录,而③会将所有满足查询条件的记录都加锁。</p><h5 id="④-即含有唯一键,也含有普通索引"><a href="#④-即含有唯一键,也含有普通索引" class="headerlink" title="④ 即含有唯一键,也含有普通索引"></a>④ 即含有唯一键,也含有普通索引</h5><p>(唯一索引和普通索引都会 加锁,其它地方使用主键加锁,死锁概率会增加)</p><h5 id="⑤-不含有索引-(聚簇索引上全部加锁)"><a href="#⑤-不含有索引-(聚簇索引上全部加锁)" class="headerlink" title="⑤ 不含有索引 (聚簇索引上全部加锁)"></a>⑤ 不含有索引 (聚簇索引上全部加锁)</h5><p><code>delete from test where id = 10;</code><br>(没有索引,只能走聚簇索引,进行全部扫描。)<br>相对于前面三个组合,这是一个比较特殊的情况。id列上没有索引,where id = 10;这个过滤条件,没法通过索引进行过滤,那么只能走全表扫描做过滤。<br><img src="/uploads/2018/11/mysql_index_03.jpg" alt=""><br>由于id列上没有索引,因此只能走聚簇索引,进行全部扫描。从图中可以看到,满足删除条件的记录有两条,但是,聚簇索引上所有的记录,都被加上了X锁。无论记录是否满足条件,全部被加上X锁。既不是加表锁,也不是在满足条件的记录上加行锁。</p><h4 id="4-死锁"><a href="#4-死锁" class="headerlink" title="4. 死锁"></a>4. 死锁</h4><p>死锁是指两个或者多个事务在同一资源上相互作用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试图以不同的顺序锁定资源时,就可能产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。</p><h5 id="(1)互锁"><a href="#(1)互锁" class="headerlink" title="(1)互锁"></a>(1)互锁</h5><p><img src="/uploads/2018/11/mysql_deadlock_01.jpg" alt=""><br>最常见的死锁,每个事务执行两条SQL,分别持有了一把锁,然后加另一把锁,产生死锁。</p><h5 id="(2)数据查询顺序导致加锁"><a href="#(2)数据查询顺序导致加锁" class="headerlink" title="(2)数据查询顺序导致加锁"></a>(2)数据查询顺序导致加锁</h5><p><img src="/uploads/2018/11/mysql_deadlock_02.jpg" alt=""><br>虽然每个Session都只有一条语句,仍旧会产生死锁。要分析这个死锁,首先必须用到本文前面提到的MySQL加锁的规则。针对Session 1,从name索引出发,读到的[hdc, 1],[hdc, 6]均满足条件,不仅会加name索引上的记录X锁,而且会加聚簇索引上的记录X锁,加锁顺序为先[1,hdc,100],后[6,hdc,10]。而Session 2,从pubtime索引出发,[10,6],[100,1]均满足过滤条件,同样也会加聚簇索引上的记录X锁,加锁顺序为[6,hdc,10],后[1,hdc,100]。发现没有,跟Session 1的加锁顺序正好相反,如果两个Session恰好都持有了第一把锁,请求加第二把锁,死锁就发生了。</p><font color="red">(注:死锁的发生与否,并不在于事务中有多少条SQL语句,死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。)</font>]]></content>
<summary type="html">
<h4 id="1-新建数据表:"><a href="#1-新建数据表:" class="headerlink" title="1. 新建数据表:"></a>1. 新建数据表:</h4><figure class="highlight plain"><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">| test | CREATE TABLE `test` (</span><br><span class="line"> `id` int(11) unsigned NOT NULL AUTO_INCREMENT,</span><br><span class="line"> `name` varchar(50) NOT NULL DEFAULT &apos;&apos;,</span><br><span class="line"> `age` tinyint(3) NOT NULL,</span><br><span class="line"> `hobby` varchar(200) NOT NULL DEFAULT &apos;&apos;,</span><br><span class="line"> PRIMARY KEY (`id`),</span><br><span class="line"> UNIQUE KEY `name` (`name`),</span><br><span class="line"> KEY `hobby` (`hobby`)</span><br><span class="line">) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 |</span><br></pre></td></tr></table></figure>
</summary>
<category term="MySQL" scheme="http://yoursite.com/categories/MySQL/"/>
<category term="MySQL" scheme="http://yoursite.com/tags/MySQL/"/>
</entry>
<entry>
<title>PHP-FPM配置文件详解</title>
<link href="http://yoursite.com/2018/10/24/PHP-FPM%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%AF%A6%E8%A7%A3/"/>
<id>http://yoursite.com/2018/10/24/PHP-FPM配置文件详解/</id>
<published>2018-10-24T09:15:18.000Z</published>
<updated>2018-10-24T09:35:04.860Z</updated>
<content type="html"><![CDATA[<blockquote><p>过滤php-fpm.conf文件中注释行。<br><code>grep -Env "^$|;" php-fpm.conf</code><br>grep - 过滤命令<br> -E - 使用正则表达示进行匹配<br> -n - 显示行号<br> -v - 剔除匹配的项(默认是筛选匹配的项)<br> ^ - 开头匹配<br> $ - 代表空行<br> | - 正则中的或运算<br> ; - ;开头行</p></blockquote><a id="more"></a><h4 id="配置文件:"><a href="#配置文件:" class="headerlink" title="配置文件:"></a>配置文件:</h4><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">[www]</span><br><span class="line">user = www#进程的发起用户和用户组,用户user是必须设置,group不是</span><br><span class="line">group = www</span><br><span class="line">listen = 127.0.0.1:9000#监听ip和端口</span><br><span class="line"></span><br><span class="line">pm = dynamic#选择进程池管理器如何控制子进程的数量</span><br><span class="line">pm.max_children = 5</span><br><span class="line">pm.start_servers = 2</span><br><span class="line">pm.min_spare_servers = 1</span><br><span class="line">pm.max_spare_servers = 3</span><br><span class="line"> </span><br><span class="line">slowlog = /opt/webserver/logs/php/$pool.log.slow #用于记录慢请求</span><br><span class="line">request_slowlog_timeout = 3#慢日志请求超时时间,对一个php程序进行跟踪。</span><br><span class="line">;request_terminate_timeout = 0 #终止请求超时时间,在worker进程被杀掉之后,提供单个请求的超时间隔。由于某种原因不停止脚本执行时,应该使用该选项,0表示关闭不启用</span><br></pre></td></tr></table></figure><blockquote><p>static: 对于子进程的开启数路给定一个锁定的值(pm.max_children)<br>dynamic: 子进程的数目为动态的,它的数目基于下面的指令的值(以下为dynamic适用参数)<br> pm.max_children: 同一时刻能够存货的最大子进程的数量<br> pm.start_servers: 在启动时启动的子进程数量<br> pm.min_spare_servers: 处于空闲”idle”状态的最小子进程,如果空闲进程数量小于这个值,那么相应的子进程会被创建<br> pm.max_spare_servers: 最大空闲子进程数量,空闲子进程数量超过这个值,那么相应的子进程会被杀掉。<br>ondemand: 在启动时不会创建,只有当发起请求链接时才会创建(pm.max_children, pm.process_idle_timeout)</p></blockquote><h4 id="总结:"><a href="#总结:" class="headerlink" title="总结:"></a>总结:</h4><p>在php-fpm的配置文件中,有两个指令非常重要,就是”pm.max_children” 和 “request_terminate_timeout”</p><p>(1)第一个指令”pm.max_children” 确定了php-fpm的处理能力,原则上时越多越好,但这个是在内存足够打的前提下,每开启一个php-fpm进程要占用近30M左右的内存<br>如果请求访问较多,那么可能会出现502,504错误。对于502错误来说,属于繁忙进程而造成的,对于504来说,就是客户发送的请求在限定的时间内没有得到相应,过多的请求导致“504 Gateway Time-out”。这里也有可能是服务器带宽问题。</p><p>(2)另外一个需要注意的指令”request_terminate_timeout”,它决定php-fpm进程的连接/发送和读取的时间,如果设置过小很容易出现”502 Bad Gateway” 和 “504 Gateway Time-out”,默认为0,就是说没有启用,不加限制,但是这种设置前提是你的php-fpm足够健康,这个需要根据实际情况加以限定</p><h4 id="附属PHP-FPM配置文件"><a href="#附属PHP-FPM配置文件" class="headerlink" title="附属PHP-FPM配置文件"></a>附属PHP-FPM配置文件</h4><figure class="highlight plain"><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><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line">pid = run/php-fpm.pid</span><br><span class="line">#pid设置,默认在安装目录中的var/run/php-fpm.pid,建议开启</span><br><span class="line"></span><br><span class="line">error_log = log/php-fpm.log</span><br><span class="line">#错误日志,默认在安装目录中的var/log/php-fpm.log</span><br><span class="line"></span><br><span class="line">log_level = notice</span><br><span class="line">#错误级别. 可用级别为: alert(必须立即处理), error(错误情况), warning(警告情况), notice(一般重要信息), debug(调试信息). 默认: notice.</span><br><span class="line"></span><br><span class="line">emergency_restart_threshold = 60</span><br><span class="line">emergency_restart_interval = 60s</span><br><span class="line">#表示在emergency_restart_interval所设值内出现SIGSEGV或者SIGBUS错误的php-cgi进程数如果超过 emergency_restart_threshold个,php-fpm就会优雅重启。这两个选项一般保持默认值。</span><br><span class="line"></span><br><span class="line">process_control_timeout = 0</span><br><span class="line">#设置子进程接受主进程复用信号的超时时间. 可用单位: s(秒), m(分), h(小时), 或者 d(天) 默认单位: s(秒). 默认值: 0.</span><br><span class="line"></span><br><span class="line">daemonize = yes</span><br><span class="line">#后台执行fpm,默认值为yes,如果为了调试可以改为no。在FPM中,可以使用不同的设置来运行多个进程池。 这些设置可以针对每个进程池单独设置。</span><br><span class="line"></span><br><span class="line">listen = 127.0.0.1:9000</span><br><span class="line">#fpm监听端口,即nginx中php处理的地址,一般默认值即可。可用格式为: 'ip:port', 'port', '/path/to/unix/socket'. 每个进程池都需要设置.</span><br><span class="line"></span><br><span class="line">listen.backlog = -1</span><br><span class="line">#backlog数,-1表示无限制,由操作系统决定,此行注释掉就行。backlog含义参考:http://www.3gyou.cc/?p=41</span><br><span class="line"></span><br><span class="line">listen.allowed_clients = 127.0.0.1</span><br><span class="line">#允许访问FastCGI进程的IP,设置any为不限制IP,如果要设置其他主机的nginx也能访问这台FPM进程,listen处要设置成本地可被访问的IP。默认值是any。每个地址是用逗号分隔. 如果没有设置或者为空,则允许任何服务器请求连接</span><br><span class="line"></span><br><span class="line">listen.owner = www</span><br><span class="line">listen.group = www</span><br><span class="line">listen.mode = 0666</span><br><span class="line">#unix socket设置选项,如果使用tcp方式访问,这里注释即可。</span><br><span class="line"></span><br><span class="line">user = www</span><br><span class="line">group = www</span><br><span class="line">#启动进程的帐户和组</span><br><span class="line"></span><br><span class="line">pm = dynamic #对于专用服务器,pm可以设置为static。</span><br><span class="line">#如何控制子进程,选项有static和dynamic。如果选择static,则由pm.max_children指定固定的子进程数。如果选择dynamic,则由下开参数决定:</span><br><span class="line">pm.max_children #,子进程最大数</span><br><span class="line">pm.start_servers #,启动时的进程数</span><br><span class="line">pm.min_spare_servers #,保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程</span><br><span class="line">pm.max_spare_servers #,保证空闲进程数最大值,如果空闲进程大于此值,此进行清理</span><br><span class="line"></span><br><span class="line">pm.max_requests = 1000</span><br><span class="line">#设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 '0' 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.</span><br><span class="line"></span><br><span class="line">pm.status_path = /status</span><br><span class="line">#FPM状态页面的网址. 如果没有设置, 则无法访问状态页面. 默认值: none. munin监控会使用到</span><br><span class="line"></span><br><span class="line">ping.path = /ping</span><br><span class="line">#FPM监控页面的ping网址. 如果没有设置, 则无法访问ping页面. 该页面用于外部检测FPM是否存活并且可以响应请求. 请注意必须以斜线开头 (/)。</span><br><span class="line"></span><br><span class="line">ping.response = pong</span><br><span class="line">#用于定义ping请求的返回相应. 返回为 HTTP 200 的 text/plain 格式文本. 默认值: pong.</span><br><span class="line"></span><br><span class="line">request_terminate_timeout = 0</span><br><span class="line">#设置单个请求的超时中止时间. 该选项可能会对php.ini设置中的'max_execution_time'因为某些特殊原因没有中止运行的脚本有用. 设置为 '0' 表示 'Off'.当经常出现502错误时可以尝试更改此选项。</span><br><span class="line"></span><br><span class="line">request_slowlog_timeout = 10s</span><br><span class="line">#当一个请求该设置的超时时间后,就会将对应的PHP调用堆栈信息完整写入到慢日志中. 设置为 '0' 表示 'Off'</span><br><span class="line"></span><br><span class="line">slowlog = log/$pool.log.slow</span><br><span class="line">#慢请求的记录日志,配合request_slowlog_timeout使用</span><br><span class="line"></span><br><span class="line">rlimit_files = 1024</span><br><span class="line">#设置文件打开描述符的rlimit限制. 默认值: 系统定义值默认可打开句柄是1024,可使用 ulimit -n查看,ulimit -n 2048修改。</span><br><span class="line"></span><br><span class="line">rlimit_core = 0</span><br><span class="line">#设置核心rlimit最大限制值. 可用值: 'unlimited' 、0或者正整数. 默认值: 系统定义值.</span><br><span class="line"></span><br><span class="line">chroot =</span><br><span class="line">#启动时的Chroot目录. 所定义的目录需要是绝对路径. 如果没有设置, 则chroot不被使用.</span><br><span class="line"></span><br><span class="line">chdir =</span><br><span class="line">#设置启动目录,启动时会自动Chdir到该目录. 所定义的目录需要是绝对路径. 默认值: 当前目录,或者/目录(chroot时)</span><br><span class="line"></span><br><span class="line">catch_workers_output = yes</span><br><span class="line">#重定向运行过程中的stdout和stderr到主要的错误日志文件中. 如果没有设置, stdout 和 stderr 将会根据FastCGI的规则被重定向到 /dev/null . 默认值: 空.</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<blockquote>
<p>过滤php-fpm.conf文件中注释行。<br><code>grep -Env &quot;^$|;&quot; php-fpm.conf</code><br>grep - 过滤命令<br> -E - 使用正则表达示进行匹配<br> -n - 显示行号<br> -v - 剔除匹配的项(默认是筛选匹配的项)<br> ^ - 开头匹配<br> $ - 代表空行<br> | - 正则中的或运算<br> ; - ;开头行</p>
</blockquote>
</summary>
<category term="服务器" scheme="http://yoursite.com/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
<category term="PHP-FPM" scheme="http://yoursite.com/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/PHP-FPM/"/>
<category term="PHP-FPM" scheme="http://yoursite.com/tags/PHP-FPM/"/>
</entry>
<entry>
<title>INI配置文件的格式</title>
<link href="http://yoursite.com/2018/10/24/INI%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E6%A0%BC%E5%BC%8F/"/>
<id>http://yoursite.com/2018/10/24/INI配置文件的格式/</id>
<published>2018-10-24T09:14:55.000Z</published>
<updated>2018-10-24T09:26:34.226Z</updated>
<content type="html"><![CDATA[<p>最近学习Go语言的时候,发现好多Go框架中的配置文件都支持INI格式的。当然,不仅仅是Go框架,PHP语言的好多框架也使用INI格式的配置文件,例如Yaf等。因此,需要梳理一下INI格式。常用的配置文件格式还有很多,如XML配置文件等。<br><a id="more"></a></p><blockquote><p>在早期的windows桌面系统中主要是用INI文件作为系统的配置文件,从win95以后开始转向使用注册表,但是还有很多系统配置是使用INI文件的。其实INI文件就是简单的text文件,只不过这种txt文件要遵循一定的INI文件格式。现在的WINCE系统上也常常用INI文件作为配置文件。“.INI ”就是英文 “initialization”的头三个字母的缩写;当然INI file的后缀名也不一定是”.ini”也可以是”.cfg”,”.conf ”或者是”.txt”。</p></blockquote><h4 id="INI文件由节、键、值组成"><a href="#INI文件由节、键、值组成" class="headerlink" title="INI文件由节、键、值组成"></a>INI文件由节、键、值组成</h4><p><strong>节</strong><br> [section] </p><p><strong>参数(键=值) </strong><br> name=value</p><p><strong>注解</strong><br> 注解使用分号表示(;)。在分号后面的文字,直到该行结尾都全部为注解。</p><font color="red">INI文件的格式很简单,最基本的三个要素是:parameters,sections和comments。</font><h4 id="什么是parameters?"><a href="#什么是parameters?" class="headerlink" title="什么是parameters?"></a>什么是parameters?</h4><p>INI所包含的最基本的“元素”就是parameter;每一个parameter都有一个name和一个value,name和value是由等号“=”隔开。name在等号的左边。<br>如:<br> name = value</p><h4 id="什么是sections-?"><a href="#什么是sections-?" class="headerlink" title="什么是sections ?"></a>什么是sections ?</h4><p>所有的parameters都是以sections为单位结合在一起的。所有的section名称都是独占一行,并且sections名字都被方括号包围着([ and ])。在section声明后的所有parameters都是属于该section。对于一个section没有明显的结束标志符,一个section的开始就是上一个section的结束,或者是end of the file。Sections一般情况下不能被nested,当然特殊情况下也可以实现sections的嵌套。<br>section如下所示:<br> [section]</p><h4 id="什么是comments-?"><a href="#什么是comments-?" class="headerlink" title="什么是comments ?"></a>什么是comments ?</h4><p>在INI文件中注释语句是以分号“;”开始的。所有的所有的注释语句不管多长都是独占一行直到结束的。在分号和行结束符之间的所有内容都是被忽略的。<br>注释实例如下:<br>;comments text</p><p>当然,上面讲的都是最经典的INI文件格式,随着使用的需求INI文件的格式也出现了很多变种;</p><h4 id="INI实例"><a href="#INI实例" class="headerlink" title="INI实例"></a>INI实例</h4><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">; last modified 1 April 2001 by John Doe</span><br><span class="line">[owner]</span><br><span class="line">name = John Doe</span><br><span class="line">organization = Acme Products</span><br><span class="line"></span><br><span class="line">[database]</span><br><span class="line">server=192.0.2.42</span><br><span class="line">; use IP address in case network name resolution is not working</span><br><span class="line">port=143</span><br><span class="line">file = "acme payroll.dat"</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>最近学习Go语言的时候,发现好多Go框架中的配置文件都支持INI格式的。当然,不仅仅是Go框架,PHP语言的好多框架也使用INI格式的配置文件,例如Yaf等。因此,需要梳理一下INI格式。常用的配置文件格式还有很多,如XML配置文件等。<br>
</summary>
<category term="服务器" scheme="http://yoursite.com/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
<category term="Nginx" scheme="http://yoursite.com/categories/%E6%9C%8D%E5%8A%A1%E5%99%A8/Nginx/"/>
<category term="Nginx" scheme="http://yoursite.com/tags/Nginx/"/>
</entry>
<entry>
<title>HTTP状态码499解析</title>
<link href="http://yoursite.com/2018/10/24/HTTP%E7%8A%B6%E6%80%81%E7%A0%81499%E8%A7%A3%E6%9E%90/"/>
<id>http://yoursite.com/2018/10/24/HTTP状态码499解析/</id>
<published>2018-10-24T09:13:51.000Z</published>
<updated>2018-10-24T09:32:04.934Z</updated>
<content type="html"><![CDATA[<p>日志记录中HTTP状态码出现499错误有多种情况,我遇到的一种情况是nginx反代到一个永远打不开的后端,就这样了,日志状态记录是499、发送字节数是0。</p><p>499错误是什么?让我们看看NGINX的源码中的定义:<br><figure class="highlight plain"><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">ngx_string(ngx_http_error_495_page), /* 495, https certificate error */</span><br><span class="line">ngx_string(ngx_http_error_496_page), /* 496, https no certificate */</span><br><span class="line">ngx_string(ngx_http_error_497_page), /* 497, http to https */</span><br><span class="line">ngx_string(ngx_http_error_404_page), /* 498, canceled */</span><br><span class="line">ngx_null_string, /* 499, client has closed connection */</span><br></pre></td></tr></table></figure></p><p>可以看到,499对应的是 “client has closed connection”。这很有可能是因为服务器端处理的时间过长,客户端“不耐烦”了。<br><a id="more"></a></p><p><strong>Nginx 499错误的原因及解决方法</strong><br>打开Nginx的access.log发现在最后一次的提交是出现了HTTP1.1 499 0 -这样的错误,在百度搜索nginx 499错误,结果都是说客户端主动断开了连接。</p><p>但经过我的测试这显然不是客户端的问题,因为使用端口+IP直接访问后端服务器不存在此问题,后来测试nginx发现如果两次提交post过快就会出现499的情况,看来是nginx认为是不安全的连接,主动拒绝了客户端的连接.</p><p>但搜索相关问题一直找不到解决方法,最后终于在google上搜索到一英文论坛上有关于此错误的解决方法:<br><figure class="highlight plain"><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">proxy_ignore_client_abort on;</span><br><span class="line">Don’t know if this is safe.</span><br></pre></td></tr></table></figure></p><p>就是说要配置参数 proxy_ignore_client_abort on;<br>表示代理服务端不要主要主动关闭客户端连接。</p><p>以此配置重启nginx,问题果然得到解决。只是安全方面稍有欠缺,但比总是出现找不到服务器好多了。</p><p>还有一种原因是 我后来测试发现 确实是客户端关闭了连接,或者说连接超时 ,无论你设置多少超时时间多没用 原来是php进程不够用了 改善一下php进程数 问题解决 默认测试环境才开5个子进程。</p>]]></content>
<summary type="html">
<p>日志记录中HTTP状态码出现499错误有多种情况,我遇到的一种情况是nginx反代到一个永远打不开的后端,就这样了,日志状态记录是499、发送字节数是0。</p>
<p>499错误是什么?让我们看看NGINX的源码中的定义:<br><figure class="highlight plain"><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">ngx_string(ngx_http_error_495_page), /* 495, https certificate error */</span><br><span class="line">ngx_string(ngx_http_error_496_page), /* 496, https no certificate */</span><br><span class="line">ngx_string(ngx_http_error_497_page), /* 497, http to https */</span><br><span class="line">ngx_string(ngx_http_error_404_page), /* 498, canceled */</span><br><span class="line">ngx_null_string, /* 499, client has closed connection */</span><br></pre></td></tr></table></figure></p>
<p>可以看到,499对应的是 “client has closed connection”。这很有可能是因为服务器端处理的时间过长,客户端“不耐烦”了。<br>
</summary>
<category term="前端" scheme="http://yoursite.com/categories/%E5%89%8D%E7%AB%AF/"/>
<category term="HTTP" scheme="http://yoursite.com/tags/HTTP/"/>
</entry>
<entry>
<title>Shell常用知识点总结</title>
<link href="http://yoursite.com/2018/10/23/Shell%E5%B8%B8%E7%94%A8%E7%9F%A5%E8%AF%86%E7%82%B9%E6%80%BB%E7%BB%93/"/>
<id>http://yoursite.com/2018/10/23/Shell常用知识点总结/</id>
<published>2018-10-23T10:42:55.000Z</published>
<updated>2018-10-23T10:49:08.709Z</updated>
<content type="html"><![CDATA[<h4 id="1、整型变量自增的几种方法"><a href="#1、整型变量自增的几种方法" class="headerlink" title="1、整型变量自增的几种方法"></a>1、整型变量自增的几种方法</h4><figure class="highlight plain"><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">a=1</span><br><span class="line">a=$(($a+1))</span><br><span class="line">a=$[$a+1]</span><br><span class="line">a=`expr $a + 1`</span><br><span class="line">let a++</span><br><span class="line">let a+=1</span><br><span class="line">((a++))</span><br><span class="line">echo $a</span><br></pre></td></tr></table></figure><a id="more"></a><h4 id="2、读取文件中的内容"><a href="#2、读取文件中的内容" class="headerlink" title="2、读取文件中的内容"></a>2、读取文件中的内容</h4><p>(1)直接读取对应文件<br><figure class="highlight plain"><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">#!/bin/bash</span><br><span class="line">while read line</span><br><span class="line">do</span><br><span class="line"> echo $line #这里可根据实际用途变化</span><br><span class="line">done < urfile</span><br></pre></td></tr></table></figure></p><p>(2)使用管道符形式读取<br><figure class="highlight plain"><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">#!/bin/bash</span><br><span class="line">cat urfile | while read line</span><br><span class="line">do</span><br><span class="line"> echo $line</span><br><span class="line">done</span><br></pre></td></tr></table></figure></p><p>(注意:以上代码中urfile 为被读取的文件)</p><p>(3)将文件赋值给变量<br><figure class="highlight plain"><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">#!/bin/bash</span><br><span class="line">last | while read wOne wTwo wThree</span><br><span class="line">do</span><br><span class="line">echo $wOne","$wTwo","$wThree</span><br><span class="line">done</span><br></pre></td></tr></table></figure></p><h4 id="3、判断文件是否为空"><a href="#3、判断文件是否为空" class="headerlink" title="3、判断文件是否为空"></a>3、判断文件是否为空</h4><p><code>if [[ ! -s filename ]]</code> # 如果文件存在且为空,-s代表存在不为空,!将它取反</p><h4 id="4、比较两个字符串的大小"><a href="#4、比较两个字符串的大小" class="headerlink" title="4、比较两个字符串的大小"></a>4、比较两个字符串的大小</h4><p>< 小于,在ASCII字母顺序下,如:<br> <code>if [[ "$a" < "$b" ]]</code><br> <code>if [ "$a" \< "$b" ]</code><br>< 大于,在ASCII字母顺序下,如:<br> <code>if [[ "$a" > "$b" ]]</code><br> <code>if [ "$a" \> "$b" ]</code><br>注意:在[]结构中”>”需要被转义。</p>]]></content>
<summary type="html">
<h4 id="1、整型变量自增的几种方法"><a href="#1、整型变量自增的几种方法" class="headerlink" title="1、整型变量自增的几种方法"></a>1、整型变量自增的几种方法</h4><figure class="highlight plain"><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">a=1</span><br><span class="line">a=$(($a+1))</span><br><span class="line">a=$[$a+1]</span><br><span class="line">a=`expr $a + 1`</span><br><span class="line">let a++</span><br><span class="line">let a+=1</span><br><span class="line">((a++))</span><br><span class="line">echo $a</span><br></pre></td></tr></table></figure>
</summary>
<category term="Shell" scheme="http://yoursite.com/categories/Shell/"/>
<category term="Shell" scheme="http://yoursite.com/tags/Shell/"/>
</entry>
<entry>
<title>Linux之常用命令集锦</title>
<link href="http://yoursite.com/2018/10/12/Linux%E4%B9%8B%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E9%9B%86%E9%94%A6/"/>
<id>http://yoursite.com/2018/10/12/Linux之常用命令集锦/</id>
<published>2018-10-12T04:24:19.000Z</published>
<updated>2018-10-23T07:16:55.815Z</updated>
<content type="html"><![CDATA[<p>Linux命令的格式是这样的:<br> <code>命令名称 [命令参数] [命令对象]</code><br>注意,命令名称、命令参数、命令对象之间请用空格键分隔。<br>命令对象一般是指要处理的文件、目录、用户等资源,而命令参数可以用长格式(完整的选项名称),也可以用短格式(单个字母的缩写),两者分别用--与-作为前缀。</p><p><strong>命令参数的长格式与短格式示例:</strong></p><table><thead><tr><th>长格式</th><th>man –help</th></tr></thead><tbody><tr><td>短格式</td><td>man -h</td></tr></tbody></table><a id="more"></a><p><strong>1、man</strong><br>man命令中常用按键以及用途</p><style> table th:first-of-type { width: 30%; }</style><table><thead><tr><th>按键</th><th>用途</th></tr></thead><tbody><tr><td>空格键</td><td>向下翻一页</td></tr><tr><td>PaGe down</td><td>向下翻一页</td></tr><tr><td>PaGe up</td><td>向上翻一页</td></tr><tr><td>home</td><td>直接前往首页</td></tr><tr><td>end</td><td>直接前往尾页</td></tr><tr><td>/</td><td>从上至下搜索某个关键词,如“/linux”</td></tr><tr><td>?</td><td>从下至上搜索某个关键词,如“?linux”</td></tr><tr><td>n</td><td>定位到下一个搜索到的关键词</td></tr><tr><td>N</td><td>定位到上一个搜索到的关键词</td></tr><tr><td>q</td><td>退出帮助文档</td></tr></tbody></table><p><strong>man 命令帮助信息的结构以及意义</strong></p><table><thead><tr><th>结构名称</th><th>代表意义</th></tr></thead><tbody><tr><td>NAME</td><td>命令的名称</td></tr><tr><td>SYNOPSIS</td><td>参数的大致使用方法</td></tr><tr><td>DESCRIPTION</td><td>介绍说明</td></tr><tr><td>EXAMPLES</td><td>演示(附带简单说明)</td></tr><tr><td>OVERVIEW</td><td>概述</td></tr><tr><td>DEFAULTS</td><td>默认的功能</td></tr><tr><td>OPTIONS</td><td>具体的可用选项(带介绍)</td></tr><tr><td>ENVIRONMENT</td><td>环境变量</td></tr><tr><td>FILES</td><td>用到的文件</td></tr><tr><td>SEE ALSO</td><td>相关的资料</td></tr><tr><td>HISTORY</td><td>维护历史与联系方式</td></tr></tbody></table><h4 id="一、常用系统工作命令"><a href="#一、常用系统工作命令" class="headerlink" title="一、常用系统工作命令"></a>一、常用系统工作命令</h4><h5 id="1、echo-选项-命令"><a href="#1、echo-选项-命令" class="headerlink" title="1、echo [选项] 命令"></a>1、echo [选项] 命令</h5><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-e</td><td>若字符串出现以下字符,则特别加以处理,而不会将它当成一般文字输出(类似一些特殊字符)</td></tr><tr><td>-n</td><td>不要在最后自动换行</td></tr></tbody></table><h5 id="2、date命令"><a href="#2、date命令" class="headerlink" title="2、date命令"></a>2、date命令</h5><p>格式: date [选项] [+指定的格式]<br>date 命令中输入以“+”号开头的参数,即可按照指定格式来输出系统的时间或日期。<br><strong>date命令中的参数以及作用</strong></p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>%t</td><td>跳格[Tab 键]</td></tr><tr><td>%Y</td><td>年</td></tr><tr><td>%m</td><td>月</td></tr><tr><td>%d</td><td>日</td></tr><tr><td>%H</td><td>小时(00~23)</td></tr><tr><td>%I</td><td>小时(00~12)</td></tr><tr><td>%M</td><td>分钟(00~59)</td></tr><tr><td>%S</td><td>秒(00~59)</td></tr><tr><td>%j</td><td>今年中的第几天</td></tr></tbody></table><h5 id="3、reboot命令"><a href="#3、reboot命令" class="headerlink" title="3、reboot命令"></a>3、reboot命令</h5><h5 id="4、poweroff命令"><a href="#4、poweroff命令" class="headerlink" title="4、poweroff命令"></a>4、poweroff命令</h5><h5 id="5、wget命令"><a href="#5、wget命令" class="headerlink" title="5、wget命令"></a>5、wget命令</h5><p>wget 命令的参数以及作用</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-b</td><td>后台下载模式</td></tr><tr><td>-P</td><td>下载到指定目录</td></tr><tr><td>-t</td><td>最大尝试次数</td></tr><tr><td>-c</td><td>断点续传</td></tr><tr><td>-p</td><td>下载页面内所有资源,包括图片、视频等</td></tr><tr><td>-r</td><td>递归下载</td></tr></tbody></table><h5 id="6、ps命令"><a href="#6、ps命令" class="headerlink" title="6、ps命令"></a>6、ps命令</h5><p>ps 命令的参数以及作用</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-a</td><td>显示所有进程(包括其他用户的进程)</td></tr><tr><td>-u</td><td>用户以及其他详细信息</td></tr><tr><td>-x</td><td>显示没有控制终端的进程</td></tr></tbody></table><h5 id="7、top命令"><a href="#7、top命令" class="headerlink" title="7、top命令"></a>7、top命令</h5><h5 id="8、pidof命令"><a href="#8、pidof命令" class="headerlink" title="8、pidof命令"></a>8、pidof命令</h5><p>用于查询某个指定服务进程的PID值。<br>格式:pidof [参数] [服务名称]</p><h5 id="9、kill命令"><a href="#9、kill命令" class="headerlink" title="9、kill命令"></a>9、kill命令</h5><p>格式:kill [参数] [进程PID]</p><h5 id="10、killall命令"><a href="#10、killall命令" class="headerlink" title="10、killall命令"></a>10、killall命令</h5><p>格式:killall [参数] [服务名称]</p><h5 id="11、ln-命令"><a href="#11、ln-命令" class="headerlink" title="11、ln 命令"></a>11、ln 命令</h5><p>用于创建链接文件,格式为“ln [选项] 目标”。</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-s</td><td>创建“符号链接”(如果不带-s 参数,则默认创建硬链接)</td></tr><tr><td>-f</td><td>强制创建文件或目录的链接</td></tr><tr><td>-i</td><td>覆盖前先询问</td></tr><tr><td>-v</td><td>显示创建链接的过程</td></tr></tbody></table><h5 id="12、scp-命令"><a href="#12、scp-命令" class="headerlink" title="12、scp 命令"></a>12、scp 命令</h5><p>scp(secure copy)是一个基于 SSH 协议在网络之间进行安全传输的命令,其格式为“scp [参数] 本地文件 远程帐户@远程 IP 地址:远程目录”。</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-v</td><td>显示详细的连接进度</td></tr><tr><td>-P</td><td>指定远程主机的 sshd 端口号</td></tr><tr><td>-r</td><td>用于传送文件夹</td></tr><tr><td>-6</td><td>使用 IPv6 协议</td></tr></tbody></table><h4 id="二、系统状态检测命令"><a href="#二、系统状态检测命令" class="headerlink" title="二、系统状态检测命令"></a>二、系统状态检测命令</h4><p>查看Linux主机公网IP<br><code>curl ifconfig.me</code></p><h5 id="1、ifconfig命令"><a href="#1、ifconfig命令" class="headerlink" title="1、ifconfig命令"></a>1、ifconfig命令</h5><p>其实主要查看的就是网卡名称、inet 参数后面的 IP 地址、ether 参数后面的网卡物理地址(又称为 MAC 地址),<br>以及 RX、TX 的接收数据包与发送数据包的个数及累计流量。<br><figure class="highlight plain"><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">[root@linuxprobe ~]# ifconfig</span><br><span class="line">eno16777728: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500</span><br><span class="line">inet 192.168.10.10 netmask 255.255.255.0 broadcast 192.168.10.255</span><br><span class="line">inet6 fe80::20c:29ff:fec4:a409 prefixlen 64 scopeid 0x20<link></span><br><span class="line">ether 00:0c:29:c4:a4:09 txqueuelen 1000 (Ethernet)</span><br><span class="line">RX packets 36 bytes 3176 (3.1 KiB)</span><br><span class="line">RX errors 0 dropped 0 overruns 0 frame 0</span><br><span class="line">TX packets 38 bytes 4757 (4.6 KiB)</span><br><span class="line">TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0</span><br></pre></td></tr></table></figure></p><h5 id="2、uname-命令"><a href="#2、uname-命令" class="headerlink" title="2、uname 命令"></a>2、uname 命令</h5><p>格式:uname [-a]</p><h5 id="3、uptime-命令"><a href="#3、uptime-命令" class="headerlink" title="3、uptime 命令"></a>3、uptime 命令</h5><p>查看系统的负载信息。格式为 uptime<br>平均负载值指的是系统在最近 1 分钟、5 分钟、15 分钟内的压力情况(下面加粗的信息部分);<br>负载值越低越好,尽量不要长期超过 1,在生产环境中不要超过 5。</p><h5 id="4、free-命令"><a href="#4、free-命令" class="headerlink" title="4、free 命令"></a>4、free 命令</h5><p>用于显示当前系统中内存的使用量信息,格式为“free [-h]”。</p><h5 id="5、who命令"><a href="#5、who命令" class="headerlink" title="5、who命令"></a>5、who命令</h5><p>用于查看当前登入主机的用户终端信息,格式为“who [参数]”。</p><h5 id="6、last命令"><a href="#6、last命令" class="headerlink" title="6、last命令"></a>6、last命令</h5><p>用于查看所有系统的登录记录,格式为“last [参数]”。</p><h5 id="7、history命令"><a href="#7、history命令" class="headerlink" title="7、history命令"></a>7、history命令</h5><p>用于显示历史执行过的命令,格式为“history [-c]”。<br>默认显示1000,如果觉得 1000 不够用,还可以自定义/etc/profile 文件中的HISTSIZE 变量值。<br>在使用 history 命令时,如果使用-c 参数则会清空所有的命令历史记录。</p><h4 id="三、工作目录切换命令"><a href="#三、工作目录切换命令" class="headerlink" title="三、工作目录切换命令"></a>三、工作目录切换命令</h4><h5 id="1、pwd"><a href="#1、pwd" class="headerlink" title="1、pwd"></a>1、pwd</h5><h5 id="2、cd"><a href="#2、cd" class="headerlink" title="2、cd"></a>2、cd</h5><h5 id="3、ls"><a href="#3、ls" class="headerlink" title="3、ls"></a>3、ls</h5><h4 id="四、文本文件编辑命令"><a href="#四、文本文件编辑命令" class="headerlink" title="四、文本文件编辑命令"></a>四、文本文件编辑命令</h4><h5 id="1、查看文件"><a href="#1、查看文件" class="headerlink" title="1、查看文件"></a>1、查看文件</h5><p>cat: 由第一行开始显示档案内容<br>tac: 从最后一行开始显示,可以看出 tac 是 cat 的反向显示!<br>nl: 显示的时候,顺便输出行号!<br>more: 一页一页的显示档案内容,以百分比的形式分页显示。<br>less 与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页!对于显示的内容可以使用”/字符”输入要查找的字符或者字符串并高亮显示。<br>head: 查看头几行<br>tail: 查看尾几行<br>od: 以二进制的方式读取档案内容!</p><h5 id="2、tr命令"><a href="#2、tr命令" class="headerlink" title="2、tr命令"></a>2、tr命令</h5><p>用于替换文本文件中的字符,格式为“tr [原始字符] [目标字符]”。</p><h5 id="3、wc命令"><a href="#3、wc命令" class="headerlink" title="3、wc命令"></a>3、wc命令</h5><p>用于统计指定文本的行数(-l)、字数(-w)、字节数(-c),格式为“wc [参数] 文本”。</p><h5 id="4、stat命令"><a href="#4、stat命令" class="headerlink" title="4、stat命令"></a>4、stat命令</h5><p>用于查看文件的具体存储信息和时间等信息,格式为“stat 文件名称”。</p><h5 id="5、cut命令"><a href="#5、cut命令" class="headerlink" title="5、cut命令"></a>5、cut命令</h5><p>用于按“列”提取文本字符,格式为“cut [参数] 文本”。<br>使用-f 参数来设置需要看的列数,还需要使用-d 参数来设置间隔符号<br>示例:<code>cut -d: -f1 /etc/passwd</code></p><h5 id="6、diff命令"><a href="#6、diff命令" class="headerlink" title="6、diff命令"></a>6、diff命令</h5><p>用于比较多个文本文件的差异,格式为“diff [参数] 文件”。</p><h4 id="五、文件目录管理命令"><a href="#五、文件目录管理命令" class="headerlink" title="五、文件目录管理命令"></a>五、文件目录管理命令</h4><h5 id="1、touch命令"><a href="#1、touch命令" class="headerlink" title="1、touch命令"></a>1、touch命令</h5><p>用于创建空白文件或设置文件的时间,格式为“touch [选项] [文件]”。</p><h5 id="2、mkdir命令"><a href="#2、mkdir命令" class="headerlink" title="2、mkdir命令"></a>2、mkdir命令</h5><p>用于创建空白的目录,格式为“mkdir [选项] 目录”。</p><h5 id="3、cp命令"><a href="#3、cp命令" class="headerlink" title="3、cp命令"></a>3、cp命令</h5><p>用于复制文件或目录,格式为“cp [选项] 源文件 目标文件”。</p><h5 id="4、mv命令"><a href="#4、mv命令" class="headerlink" title="4、mv命令"></a>4、mv命令</h5><p>用于剪切文件或将文件重命名,格式为“mv [选项] 源文件 [目标路径|目标文件名]”。</p><h5 id="5、rm命令"><a href="#5、rm命令" class="headerlink" title="5、rm命令"></a>5、rm命令</h5><p>用于删除文件或目录,格式为“rm [选项] 文件”。</p><h5 id="6、dd命令"><a href="#6、dd命令" class="headerlink" title="6、dd命令"></a>6、dd命令</h5><p>用于按照指定大小和个数的数据块来复制文件或转换文件,格式为“dd [参数]”。<br>dd 命令的参数及其作用</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>if</td><td>输入的文件名称</td></tr><tr><td>of</td><td>输出的文件名称</td></tr><tr><td>bs</td><td>设置每个“块”的大小</td></tr><tr><td>count</td><td>设置要复制“块”的个数</td></tr></tbody></table><p>Linux系统中有一个名为/dev/zero 的设备文件,这个文件不会占用系统存储空间,但却可以提供无穷无尽的数据,因此可以使用它作为 dd命令的输入文件,来生成一个指定大小的文件。<br>例如我们可以用 dd 命令从/dev/zero 设备文件中取出一个大小为 560MB 的数据块,然后保存成名为 560_file 的文件。<br><code>dd if=/dev/zero of=560_file count=1 bs=560MB</code></p><h5 id="7、file命令"><a href="#7、file命令" class="headerlink" title="7、file命令"></a>7、file命令</h5><p>用于查看文件的类型,格式为“file 文件名”。</p><h4 id="六、打包压缩与搜索命令"><a href="#六、打包压缩与搜索命令" class="headerlink" title="六、打包压缩与搜索命令"></a>六、打包压缩与搜索命令</h4><h5 id="1、tar-命令"><a href="#1、tar-命令" class="headerlink" title="1、tar 命令"></a>1、tar 命令</h5><p>用于对文件进行打包压缩或解压,格式为“tar [选项] [文件]”。<br>tar 命令的参数及其作用</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-c</td><td>创建压缩文件</td></tr><tr><td>-x</td><td>解开压缩文件</td></tr><tr><td>-t</td><td>查看压缩包内有哪些文件</td></tr><tr><td>-z</td><td>用 Gzip 压缩或解压</td></tr><tr><td>-j</td><td>用 bzip2 压缩或解压</td></tr><tr><td>-v</td><td>显示压缩或解压的过程</td></tr><tr><td>-f</td><td>目标文件名</td></tr><tr><td>-p</td><td>保留原始的权限与属性</td></tr><tr><td>-P</td><td>使用绝对路径来压缩</td></tr><tr><td>-C</td><td>指定解压到的目录</td></tr></tbody></table><p>注:-c 参数用于创建压缩文件,-x 参数用于解压文件,因此这两个参数不能同时使用。</p><p>非常推荐使用-v 参数向用户不断显示压缩或解压的过程。</p><ul><li>-C 参数用于指定要解压到哪个指定的目录。</li><li>-f 参数特别重要,它必须放到参数的最后一位,代表要压缩或解压的软件包名称。</li></ul><p>常用组合命令:<br><code>tar -czvf 压缩包名称.tar.gz 要打包的目录</code><br><code>tar -xzvf 压缩包名称.tar.gz -C 解压到的目录</code></p><h5 id="2、grep命令"><a href="#2、grep命令" class="headerlink" title="2、grep命令"></a>2、grep命令</h5><p>用于在文本中执行关键词搜索,并显示匹配的结果,格式为“grep [选项] [文件]”。<br>grep 命令的参数及其作用</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-b</td><td>将可执行文件(binary)当作文本文件(text)来搜索</td></tr><tr><td>-c</td><td>仅显示找到的行数</td></tr><tr><td>-i</td><td>忽略大小写</td></tr><tr><td>-n</td><td>显示行号</td></tr><tr><td>-v</td><td>反向选择—仅列出没有“关键词”的行</td></tr></tbody></table><p>最常用的参数:-n 参数用来显示搜索到信息的行号;-v 参数用于反选信息(即没有包含关键词的所有信息行)。</p><h5 id="3、find命令"><a href="#3、find命令" class="headerlink" title="3、find命令"></a>3、find命令</h5><p>用于按照指定条件来查找文件,格式为“find [查找路径] 寻找条件 操作”。<br>find 命令中的参数以及作用</p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-name</td><td>匹配名称</td></tr><tr><td>-perm</td><td>匹配权限(mode 为完全匹配,-mode 为包含即可)</td></tr><tr><td>-user</td><td>匹配所有者</td></tr><tr><td>-group</td><td>匹配所有组</td></tr><tr><td>-mtime -n +n</td><td>匹配修改内容的时间(-n 指 n 天以内,+n 指 n 天以前)</td></tr><tr><td>-atime -n +n</td><td>匹配访问文件的时间(-n 指 n 天以内,+n 指 n 天以前)</td></tr><tr><td>-ctime -n +n</td><td>匹配修改文件权限的时间(-n 指 n 天以内,+n 指 n 天以前)</td></tr><tr><td>-nouser</td><td>匹配无所有者的文件</td></tr><tr><td>-nogroup</td><td>匹配无所有组的文件</td></tr><tr><td>-newer f1 !f2</td><td>匹配比文件 f1 新但比 f2 旧的文件</td></tr><tr><td>–type b/d/c/p/l/f</td><td>匹配文件类型(后面的字母参数依次表示块设备、目录、字符设备、管道、链接文件、文本文件)</td></tr><tr><td>-size</td><td>匹配文件的大小(+50KB 为查找超过 50KB 的文件,而-50KB 为查找小于 50KB 的文件)</td></tr><tr><td>-prune</td><td>忽略某个目录</td></tr><tr><td>-exec …… {}\;</td><td>后面可跟用于进一步处理搜索结果的命令(下文会有演示)</td></tr></tbody></table><blockquote><p>重点是 “-exec {} \;” 参数,其中的{}表示find命令搜索出的每一个文件,并且命令的结尾必须是“\;”。<br><code>[root@linuxprobe ~]# find / -user linuxprobe -exec cp -a {} /root/findresults/ \;</code></p></blockquote>]]></content>
<summary type="html">
<p>Linux命令的格式是这样的:<br> <code>命令名称 [命令参数] [命令对象]</code><br>注意,命令名称、命令参数、命令对象之间请用空格键分隔。<br>命令对象一般是指要处理的文件、目录、用户等资源,而命令参数可以用长格式(完整的选项名称),也可以用短格式(单个字母的缩写),两者分别用--与-作为前缀。</p>
<p><strong>命令参数的长格式与短格式示例:</strong></p>
<table>
<thead>
<tr>
<th>长格式</th>
<th>man –help</th>
</tr>
</thead>
<tbody>
<tr>
<td>短格式</td>
<td>man -h</td>
</tr>
</tbody>
</table>
</summary>
<category term="书籍" scheme="http://yoursite.com/categories/%E4%B9%A6%E7%B1%8D/"/>
<category term="《Linux就该这么学》" scheme="http://yoursite.com/categories/%E4%B9%A6%E7%B1%8D/%E3%80%8ALinux%E5%B0%B1%E8%AF%A5%E8%BF%99%E4%B9%88%E5%AD%A6%E3%80%8B/"/>
<category term="书籍" scheme="http://yoursite.com/tags/%E4%B9%A6%E7%B1%8D/"/>
<category term="Linux" scheme="http://yoursite.com/tags/Linux/"/>
</entry>
<entry>
<title>Linux之常用知识点总结</title>
<link href="http://yoursite.com/2018/10/12/Linux%E4%B9%8B%E5%B8%B8%E7%94%A8%E7%9F%A5%E8%AF%86%E7%82%B9%E6%80%BB%E7%BB%93/"/>
<id>http://yoursite.com/2018/10/12/Linux之常用知识点总结/</id>
<published>2018-10-12T04:24:05.000Z</published>
<updated>2018-10-12T06:53:35.649Z</updated>
<content type="html"><![CDATA[<h4 id="1、重置root管理员密码"><a href="#1、重置root管理员密码" class="headerlink" title="1、重置root管理员密码"></a>1、重置root管理员密码</h4><p><code>cat /etc/redhat-release</code> 查看系统信息<br>(1)重启 Linux 系统主机并出现引导界面时,按下键盘上的 e 键进入内核编辑界面<br>(2)在 linux16 参数这行的最后面追加“rd.break”参数,然后按下 Ctrl + X 组合键来运行修<br>改过的内核程序<br>(3)大约 30 秒过后,进入到系统的紧急求援模式<br>(4)依次输入以下命令,等待系统重启操作完毕,然后就可以使用新密码 linuxprobe 来登录<br>Linux 系统了。<br><figure class="highlight plain"><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">mount -o remount,rw /sysroot</span><br><span class="line">chroot /sysroot</span><br><span class="line">passwd</span><br><span class="line">touch /.autorelabel</span><br><span class="line">exit</span><br><span class="line">reboot</span><br></pre></td></tr></table></figure></p><a id="more"></a><h4 id="2、常用的RPM软件包命令"><a href="#2、常用的RPM软件包命令" class="headerlink" title="2、常用的RPM软件包命令"></a>2、常用的RPM软件包命令</h4><table><thead><tr><th>命令</th><th>作用</th></tr></thead><tbody><tr><td>安装软件的命令格式</td><td>rpm -ivh filename.rpm</td></tr><tr><td>升级软件的命令格式</td><td>rpm -Uvh filename.rpm</td></tr><tr><td>卸载软件的命令格式</td><td>rpm -e filename.rpm</td></tr><tr><td>查询软件描述信息的命令格式</td><td>rpm -qpi filename.rpm</td></tr><tr><td>列出软件文件信息的命令格式</td><td>rpm -qpl filename.rpm</td></tr><tr><td>查询文件属于哪个 RPM 的命令格式</td><td>rpm -qf filename</td></tr></tbody></table><h4 id="3、常见的Yum命令"><a href="#3、常见的Yum命令" class="headerlink" title="3、常见的Yum命令"></a>3、常见的Yum命令</h4><table><thead><tr><th>命令</th><th>作用</th></tr></thead><tbody><tr><td>yum repolist all</td><td>列出所有仓库</td></tr><tr><td>yum list all</td><td>列出仓库中所有软件包</td></tr><tr><td>yum info 软件包名称 查</td><td>看软件包信息</td></tr><tr><td>yum install 软件包名称</td><td>安装软件包</td></tr><tr><td>yum reinstall 软件包名称</td><td>重新安装软件包</td></tr><tr><td>yum update 软件包名称</td><td>升级软件包</td></tr><tr><td>yum remove 软件包名称</td><td>移除软件包</td></tr><tr><td>yum clean all</td><td>清除所有仓库缓存</td></tr><tr><td>yum check-update</td><td>检查可更新的软件包</td></tr><tr><td>yum grouplist</td><td>查看系统中已经安装的软件包组</td></tr><tr><td>yum groupinstall 软件包组</td><td>安装指定的软件包组</td></tr><tr><td>yum groupremove 软件包组</td><td>移除指定的软件包组</td></tr><tr><td>yum groupinfo 软件包组</td><td>查询指定的软件包组信息</td></tr></tbody></table><h4 id="4、RHEL7-systemctl常用命令"><a href="#4、RHEL7-systemctl常用命令" class="headerlink" title="4、RHEL7 systemctl常用命令"></a>4、RHEL7 systemctl常用命令</h4><p><strong>systemctl 管理服务的启动、重启、停止、重载、查看状态等常用命令</strong></p><table><thead><tr><th>System V init(RHEL 6)</th><th>systemctl RHEL 7</th><th>作用</th></tr></thead><tbody><tr><td>service foo start</td><td>systemctl start foo.service</td><td>启动服务</td></tr><tr><td>service foo restart</td><td>systemctl restart foo.service</td><td>重启服务</td></tr><tr><td>service foo stop</td><td>systemctl stop foo.service</td><td>停止服务</td></tr><tr><td>service foo reload</td><td>systemctl reload foo.service</td><td>重新加载配置文件(不终止服务)</td></tr><tr><td>service foo status</td><td>systemctl status foo.service</td><td>查看服务状态</td></tr></tbody></table><p><strong>systemctl 设置服务开机启动、不启动、查看各级别下服务启动状态等常用命令</strong></p><table><thead><tr><th>System V init(RHEL 6)</th><th>systemctl RHEL 7</th><th>作用</th></tr></thead><tbody><tr><td>chkconfig foo on</td><td>systemctl enable foo.service</td><td>开机自动启动</td></tr><tr><td>chkconfig foo off</td><td>systemctl disable foo.service</td><td>开机不自动启动</td></tr><tr><td>chkconfig foo</td><td>systemctl is-enabled foo.service</td><td>查看特定服务是否为开机自动启动</td></tr><tr><td>chkconfig –list</td><td>systemctl list-unit-files –type=service</td><td>查看各个级别下服务的启动与禁用情况</td></tr></tbody></table><h4 id="5、输入、输出重定向"><a href="#5、输入、输出重定向" class="headerlink" title="5、输入、输出重定向"></a>5、输入、输出重定向</h4><p><strong>输入重定向中用到的符号及其作用</strong></p><table><thead><tr><th>符号</th><th>作用</th></tr></thead><tbody><tr><td>命令 < 文件</td><td>将文件作为命令的标准输入</td></tr><tr><td>命令 << 分界符</td><td>从标准输入中读入,直到遇见分界符才停止</td></tr><tr><td>命令 < 文件 1 > 文件2</td><td>将文件 1 作为命令的标准输入并将标准输出到文件 2</td></tr></tbody></table><p><strong>输出重定向中用到的符号及其作用</strong></p><table><thead><tr><th>符号</th><th>作用</th></tr></thead><tbody><tr><td>命令 > 文件</td><td>将标准输出重定向到一个文件中(清空原有文件的数据)</td></tr><tr><td>命令 2> 文件</td><td>将错误输出重定向到一个文件中(清空原有文件的数据)</td></tr><tr><td>命令 >> 文件</td><td>将标准输出重定向到一个文件中(追加到原有内容的后面)</td></tr><tr><td>命令 2>> 文件</td><td>将错误输出重定向到一个文件中(追加到原有内容的后面)</td></tr><tr><td>命令 >> 文件 2>&1 或 命令 &>> 文件</td><td>将标准输出与错误输出共同写入到文件中(追加到原有内容的后面)</td></tr></tbody></table><h4 id="6、常用的转义字符"><a href="#6、常用的转义字符" class="headerlink" title="6、常用的转义字符"></a>6、常用的转义字符</h4><p><strong>4 个最常用的转义字符如下所示。</strong></p><ul><li>反斜杠(\):使反斜杠后面的一个变量变为单纯的字符串。</li><li>单引号(’’):转义其中所有的变量为单纯的字符串。</li><li>双引号(””):保留其中的变量属性,不进行转义处理。</li><li>反引号(``):把其中的命令执行后返回结果。</li></ul><h4 id="7、Linux-系统中最重要的-10-个环境变量"><a href="#7、Linux-系统中最重要的-10-个环境变量" class="headerlink" title="7、Linux 系统中最重要的 10 个环境变量"></a>7、Linux 系统中最重要的 10 个环境变量</h4><table><thead><tr><th>变量名称</th><th>作用</th></tr></thead><tbody><tr><td>HOME</td><td>用户的主目录(即家目录)</td></tr><tr><td>SHELL</td><td>用户在使用的 Shell 解释器名称</td></tr><tr><td>HISTSIZE</td><td>输出的历史命令记录条数</td></tr><tr><td>HISTFILESIZE</td><td>保存的历史命令记录条数</td></tr><tr><td>MAIL</td><td>邮件保存路径</td></tr><tr><td>LANG</td><td>系统语言、语系名称</td></tr><tr><td>RANDOM</td><td>生成一个随机数字</td></tr><tr><td>PS1</td><td>Bash解释器的提示符</td></tr><tr><td>PATH</td><td>定义解释器搜索用户执行命令的路径</td></tr><tr><td>EDITOR</td><td>用户默认的文本编辑器</td></tr></tbody></table><h4 id="8、Linux系统中常见的目录名称以及相应内容"><a href="#8、Linux系统中常见的目录名称以及相应内容" class="headerlink" title="8、Linux系统中常见的目录名称以及相应内容"></a>8、Linux系统中常见的目录名称以及相应内容</h4><table><thead><tr><th>目录名称</th><th>应放置文件的内容</th></tr></thead><tbody><tr><td>/boot</td><td>开启所需文件——内核、开机菜单以及所需配置文件等</td></tr><tr><td>/dev</td><td>以文件形式存放任何设备与接口</td></tr><tr><td>/etc</td><td>配置文件</td></tr><tr><td>/home</td><td>用户家目录</td></tr><tr><td>/bin</td><td>存放单用户模式下还可以操作的命令</td></tr><tr><td>/lib</td><td>开机时用到的函数库,以及/bin与/sbin下面的命令要调用的函数</td></tr><tr><td>/sbin</td><td>开机过程中需要的命令</td></tr><tr><td>/media</td><td>用于挂载设备文件的目录</td></tr><tr><td>/opt</td><td>放置第三方的软件</td></tr><tr><td>/root</td><td>系统管理员的家目录</td></tr><tr><td>/srv</td><td>一些网络服务的数据文件目录</td></tr><tr><td>/tmp</td><td>任何人均可使用的“共享”临时目录</td></tr><tr><td>/proc</td><td>虚拟文件系统,例如系统内核、进程、外部设备及网络状态等</td></tr><tr><td>/usr/local</td><td>用户自行安装的软件</td></tr><tr><td>/usr/sbin</td><td>Linux系统开机时不会使用到的软件/命令/脚本</td></tr><tr><td>/usr/share</td><td>帮助与说明文件,也可放置共享文件</td></tr><tr><td>/var</td><td>主要存放经常变化的文件,如日志</td></tr><tr><td>/lost+found</td><td>当文件系统发生错误时,将一些丢失的文件片段存放在这里</td></tr></tbody></table>]]></content>
<summary type="html">
<h4 id="1、重置root管理员密码"><a href="#1、重置root管理员密码" class="headerlink" title="1、重置root管理员密码"></a>1、重置root管理员密码</h4><p><code>cat /etc/redhat-release</code> 查看系统信息<br>(1)重启 Linux 系统主机并出现引导界面时,按下键盘上的 e 键进入内核编辑界面<br>(2)在 linux16 参数这行的最后面追加“rd.break”参数,然后按下 Ctrl + X 组合键来运行修<br>改过的内核程序<br>(3)大约 30 秒过后,进入到系统的紧急求援模式<br>(4)依次输入以下命令,等待系统重启操作完毕,然后就可以使用新密码 linuxprobe 来登录<br>Linux 系统了。<br><figure class="highlight plain"><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">mount -o remount,rw /sysroot</span><br><span class="line">chroot /sysroot</span><br><span class="line">passwd</span><br><span class="line">touch /.autorelabel</span><br><span class="line">exit</span><br><span class="line">reboot</span><br></pre></td></tr></table></figure></p>
</summary>
<category term="书籍" scheme="http://yoursite.com/categories/%E4%B9%A6%E7%B1%8D/"/>
<category term="《Linux就该这么学》" scheme="http://yoursite.com/categories/%E4%B9%A6%E7%B1%8D/%E3%80%8ALinux%E5%B0%B1%E8%AF%A5%E8%BF%99%E4%B9%88%E5%AD%A6%E3%80%8B/"/>
<category term="书籍" scheme="http://yoursite.com/tags/%E4%B9%A6%E7%B1%8D/"/>
<category term="Linux" scheme="http://yoursite.com/tags/Linux/"/>
</entry>
<entry>
<title>Linux之用户身份与权限</title>
<link href="http://yoursite.com/2018/10/12/Linux%E4%B9%8B%E7%94%A8%E6%88%B7%E8%BA%AB%E4%BB%BD%E4%B8%8E%E6%9D%83%E9%99%90/"/>
<id>http://yoursite.com/2018/10/12/Linux之用户身份与权限/</id>
<published>2018-10-12T04:23:54.000Z</published>
<updated>2018-10-12T06:39:45.505Z</updated>
<content type="html"><![CDATA[<p>在RHEL 7系统中,用户身份有下面这些:</p><ul><li>管理员UID为0:系统的管理员用户。</li><li>系统用户UID为1~999:Linux系统为了避免因某个服务程序出现漏洞而被黑客提权至整台服务器,默认服务程序会有独立的系统用户负责运行,进而有效控制被破坏范围。</li><li>普通用户UID从1000开始:是由管理员创建的用于日常工作的用户。</li></ul><p>Linux系统中创建每个用户时,将自动创建一个与其同名的基本用户组,而且这个基本用户组只有该用户一个人。<br>如果该用户以后被归纳入其他用户组,则这个其他用户组称之为扩展用户组。<br>(注:一个用户只有一个基本用户组,但是可以有多个扩展用户组。)<br><a id="more"></a></p><h4 id="一、常用命令"><a href="#一、常用命令" class="headerlink" title="一、常用命令"></a>一、常用命令</h4><h5 id="1、useradd-命令"><a href="#1、useradd-命令" class="headerlink" title="1、useradd 命令"></a>1、useradd 命令</h5><p>用于创建新的用户,格式为“useradd [选项] 用户名”。<br><strong>useradd 命令中的用户参数以及作用</strong></p><style>table th:first-of-type { width: 20%;}</style><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-d</td><td>指定用户的家目录(默认为/home/username)</td></tr><tr><td>-e</td><td>账户的到期时间,格式为YYYY-MM-DD</td></tr><tr><td>-u</td><td>指定改用户的默认UID</td></tr><tr><td>-g</td><td>指定一个初始的用户基本组(必须已存在)</td></tr><tr><td>-G</td><td>指定一个或多个扩展用户组</td></tr><tr><td>-N</td><td>不创建与用户同名的基本用户组</td></tr><tr><td>-s</td><td>指定该用户的默认Shell解释器</td></tr></tbody></table><h5 id="2、groupadd-命令"><a href="#2、groupadd-命令" class="headerlink" title="2、groupadd 命令"></a>2、groupadd 命令</h5><p>用于创建用户组,格式为“groupadd [选项] 群组名”。</p><h5 id="3、usermod-命令"><a href="#3、usermod-命令" class="headerlink" title="3、usermod 命令"></a>3、usermod 命令</h5><p>用于修改用户的属性,格式为“usermod [选项] 用户名”。<br><strong>usermod 命令中的参数及作用</strong></p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-c</td><td>填写用户账户的备注信息</td></tr><tr><td>-d -m</td><td>参数-m 与参数-d 连用,可重新指定用户的家目录并自动把旧的数据转移过去</td></tr><tr><td>-e</td><td>账户的到期时间,格式为 YYYY-MM-DD</td></tr><tr><td>-g</td><td>变更所属用户组</td></tr><tr><td>-G</td><td>变更扩展用户组</td></tr><tr><td>-L</td><td>锁定用户禁止其登录系统</td></tr><tr><td>-U</td><td>解锁用户,允许其登录系统</td></tr><tr><td>-s</td><td>变更默认终端</td></tr><tr><td>-u</td><td>修改用户的 UID</td></tr></tbody></table><h5 id="4、passwd-命令"><a href="#4、passwd-命令" class="headerlink" title="4、passwd 命令"></a>4、passwd 命令</h5><p>用于修改用户密码、过期时间、认证信息等,格式为“passwd [选项] [用户名]”。<br><strong>passwd 命令中的参数以及作用</strong></p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-l</td><td>锁定用户,禁止其登录</td></tr><tr><td>-u</td><td>解除锁定,允许用户登录</td></tr><tr><td>–stdin</td><td>允许通过标准输入修改用户密码,如 echo “NewPassWord” | passwd –stdin Username</td></tr><tr><td>-d</td><td>使该用户可用空密码登录系统</td></tr><tr><td>-e</td><td>强制用户在下次登录时修改密码</td></tr><tr><td>-S</td><td>显示用户的密码是否被锁定,以及密码所采用的加密算法名称</td></tr></tbody></table><h5 id="5、userdel-命令"><a href="#5、userdel-命令" class="headerlink" title="5、userdel 命令"></a>5、userdel 命令</h5><p>用于删除用户,格式为“userdel [选项] 用户名”。<br><strong>userdel 命令的参数以及作用</strong></p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-f</td><td>强制删除用户</td></tr><tr><td>-r</td><td>同时删除用户及用户家目录</td></tr></tbody></table><h4 id="二、文件权限与归属"><a href="#二、文件权限与归属" class="headerlink" title="二、文件权限与归属"></a>二、文件权限与归属</h4><p>Linux系统中一切都是文件。文件的类型不尽相同,因此Linux系统使用了不同的字符来加以区分,常见的字符如下所示:</p><ul><li>-: 普通文件</li><li>d: 目录文件</li><li>l: 链接文件</li><li>b: 块设备文件</li><li>c: 字符设备文件</li><li>p: 管道文件</li></ul><p>在 Linux 系统中,每个文件都有所属的所有者和所有组,并且规定了文件的所有者、所有组以及其他人对文件所拥有的可读(r)、可写(w)、可执行(x)等权限。<br>对于一般文件来说,权限比较容易理解:“可读”表示能够读取文件的实际内容;“可写”表示能够编辑、新增、修改、删除文件的实际内容;“可执行”则表示能够运行一个脚本程序。<br>对目录文件来说,“可读”表示能够读取目录内的文件列表;“可写”表示能够在目录内新增、删除、重命名文件;而“可执行”则表示能够进入该目录。</p><h4 id="三、文件的特殊权限"><a href="#三、文件的特殊权限" class="headerlink" title="三、文件的特殊权限"></a>三、文件的特殊权限</h4><h5 id="1、SUID(待补充)"><a href="#1、SUID(待补充)" class="headerlink" title="1、SUID(待补充)"></a>1、SUID(待补充)</h5><h5 id="2、SGID(待补充)"><a href="#2、SGID(待补充)" class="headerlink" title="2、SGID(待补充)"></a>2、SGID(待补充)</h5><h5 id="3、SBIT"><a href="#3、SBIT" class="headerlink" title="3、SBIT"></a>3、SBIT</h5><p>SBIT 特殊权限位可确保用户只能删除自己的文件,而不能删除其他用户的文件。</p><h5 id="4、文件的隐藏属性"><a href="#4、文件的隐藏属性" class="headerlink" title="4、文件的隐藏属性"></a>4、文件的隐藏属性</h5><h6 id="(1)chattr-命令"><a href="#(1)chattr-命令" class="headerlink" title="(1)chattr 命令"></a>(1)chattr 命令</h6><p>用于设置文件的隐藏权限,格式为“chattr [参数] 文件”。<br>如果想要把某个隐藏功能添加到文件上,则需要在命令后面追加“+参数”,<br>如果想要把某个隐藏功能移出文件,则需要追加“-参数”。<br><strong>chattr 命令中用于隐藏权限的参数及其作用</strong></p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>i</td><td>无法对文件进行修改;若对目录设置了该参数,则仅能修改其中的子文件内容而不能新建或删除文件</td></tr><tr><td>a</td><td>仅允许补充(追加)内容,无法覆盖/删除内容(Append Only)</td></tr><tr><td>S</td><td>文件内容在变更后立即同步到硬盘(sync)</td></tr><tr><td>s</td><td>彻底从硬盘中删除,不可恢复(用 0 填充原文件所在硬盘区域)</td></tr><tr><td>A</td><td>不再修改这个文件或目录的最后访问时间(atime)</td></tr><tr><td>b</td><td>不再修改文件或目录的存取时间</td></tr><tr><td>D</td><td>检查压缩文件中的错误</td></tr><tr><td>d</td><td>使用 dump 命令备份时忽略本文件/目录</td></tr><tr><td>c</td><td>默认将文件或目录进行压缩</td></tr><tr><td>u</td><td>当删除该文件后依然保留其在硬盘中的数据,方便日后恢复</td></tr><tr><td>t</td><td>让文件系统支持尾部合并(tail-merging)</td></tr><tr><td>X</td><td>可以直接访问压缩文件中的内容</td></tr></tbody></table><h6 id="(2)lsattr-命令"><a href="#(2)lsattr-命令" class="headerlink" title="(2)lsattr 命令"></a>(2)lsattr 命令</h6><p>用于显示文件的隐藏权限,格式为“lsattr [参数] 文件”。</p><h5 id="5、su-命令与sudo服务"><a href="#5、su-命令与sudo服务" class="headerlink" title="5、su 命令与sudo服务"></a>5、su 命令与sudo服务</h5><h6 id="(1)su-命令与用户名之间有一个减号(-),这意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。"><a href="#(1)su-命令与用户名之间有一个减号(-),这意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。" class="headerlink" title="(1)su 命令与用户名之间有一个减号(-),这意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。"></a>(1)su 命令与用户名之间有一个减号(-),这意味着完全切换到新的用户,即把环境变量信息也变更为新用户的相应信息,而不是保留原始的信息。强烈建议在切换用户身份时添加这个减号(-)。</h6><p>(注:当从 root 管理员切换到普通用户时是不需要密码验证的,而从普通用户切换成 root管理员就需要进行密码验证了;)</p><h6 id="(2)sudo-命令把特定命令的执行权限赋予给指定用户"><a href="#(2)sudo-命令把特定命令的执行权限赋予给指定用户" class="headerlink" title="(2)sudo 命令把特定命令的执行权限赋予给指定用户"></a>(2)sudo 命令把特定命令的执行权限赋予给指定用户</h6><p>用于给普通用户提供额外的权限来完成原本 root 管理员才能完成的任务,格式为“sudo [参数] 命令名称”。<br><strong>sudo 服务中的可用参数以及作用</strong></p><table><thead><tr><th>参数</th><th>作用</th></tr></thead><tbody><tr><td>-h</td><td>列出帮助信息</td></tr><tr><td>-l</td><td>列出当前用户可执行的命令</td></tr><tr><td>-u</td><td>用户名或 UID 值 以指定的用户身份执行命令</td></tr><tr><td>-k</td><td>清空密码的有效时间,下次执行 sudo 时需要再次进行密码验证</td></tr><tr><td>-b</td><td>在后台执行指定的命令</td></tr><tr><td>-p</td><td>更改询问密码的提示语</td></tr></tbody></table><p><strong>总结来说,sudo 命令具有如下功能:</strong></p><ul><li>限制用户执行指定的命令:</li><li>记录用户执行的每一条命令;</li><li>配置文件(/etc/sudoers)提供集中的用户管理、权限与主机等参数;</li><li>验证密码的后 5 分钟内(默认值)无须再让用户再次验证密码。</li></ul><p><strong>修改sudo服务的配置文件:</strong><br>(注:只有root管理员才可以使用)</p><ol><li>使用visudo 命令打开 /etc/sudoers文件并编辑。</li><li>在<code>root ALL=(ALL) ALL</code> 改行下面新增加一行,修改对应用户名称</li><li>到此即可使用sudo服务,但是需要输入用户密码。免密使用可添加 NOPASSWD:ALL即可。</li></ol>]]></content>
<summary type="html">
<p>在RHEL 7系统中,用户身份有下面这些:</p>
<ul>
<li>管理员UID为0:系统的管理员用户。</li>
<li>系统用户UID为1~999:Linux系统为了避免因某个服务程序出现漏洞而被黑客提权至整台服务器,默认服务程序会有独立的系统用户负责运行,进而有效控制被破坏范围。</li>
<li>普通用户UID从1000开始:是由管理员创建的用于日常工作的用户。</li>
</ul>
<p>Linux系统中创建每个用户时,将自动创建一个与其同名的基本用户组,而且这个基本用户组只有该用户一个人。<br>如果该用户以后被归纳入其他用户组,则这个其他用户组称之为扩展用户组。<br>(注:一个用户只有一个基本用户组,但是可以有多个扩展用户组。)<br>
</summary>
<category term="书籍" scheme="http://yoursite.com/categories/%E4%B9%A6%E7%B1%8D/"/>
<category term="《Linux就该这么学》" scheme="http://yoursite.com/categories/%E4%B9%A6%E7%B1%8D/%E3%80%8ALinux%E5%B0%B1%E8%AF%A5%E8%BF%99%E4%B9%88%E5%AD%A6%E3%80%8B/"/>
<category term="书籍" scheme="http://yoursite.com/tags/%E4%B9%A6%E7%B1%8D/"/>
<category term="Linux" scheme="http://yoursite.com/tags/Linux/"/>
</entry>
<entry>
<title>Docker之Dockerfile配置LNMP服务实战篇</title>
<link href="http://yoursite.com/2018/09/30/Docker%E4%B9%8BDockerfile%E9%85%8D%E7%BD%AELNMP%E6%9C%8D%E5%8A%A1%E5%AE%9E%E6%88%98%E7%AF%87/"/>
<id>http://yoursite.com/2018/09/30/Docker之Dockerfile配置LNMP服务实战篇/</id>
<published>2018-09-30T04:13:48.000Z</published>
<updated>2018-09-30T04:16:43.582Z</updated>
<content type="html"><![CDATA[<p>参考博客:<a href="http://blog.51cto.com/zpf666/1905555" target="_blank" rel="noopener">传送门</a><br>supervisor:<a href="https://www.cnblogs.com/zhoujinyi/p/6073705.html" target="_blank" rel="noopener">传送门</a><br>详细Dockers学习记录参考:<a href="https://www.cnblogs.com/CloudMan6/tag/%E5%AE%B9%E5%99%A8/default.html?page=10" target="_blank" rel="noopener">传送门</a></p><p>待整理…</p>]]></content>
<summary type="html">
<p>参考博客:<a href="http://blog.51cto.com/zpf666/1905555" target="_blank" rel="noopener">传送门</a><br>supervisor:<a href="https://www.cnblogs.com
</summary>
<category term="Docker" scheme="http://yoursite.com/categories/Docker/"/>
<category term="Docker" scheme="http://yoursite.com/tags/Docker/"/>
</entry>
<entry>
<title>Docker之手动配置LNMP服务实战篇</title>
<link href="http://yoursite.com/2018/09/30/Docker%E4%B9%8B%E6%89%8B%E5%8A%A8%E9%85%8D%E7%BD%AELNMP%E6%9C%8D%E5%8A%A1%E5%AE%9E%E6%88%98%E7%AF%87/"/>
<id>http://yoursite.com/2018/09/30/Docker之手动配置LNMP服务实战篇/</id>
<published>2018-09-30T04:01:07.000Z</published>
<updated>2018-09-30T04:07:04.253Z</updated>
<content type="html"><![CDATA[<p>参考博客:<a href="https://blog.csdn.net/xy752068432/article/details/75975065" target="_blank" rel="noopener">传送门</a></p><h5 id="1、安装MySQL"><a href="#1、安装MySQL" class="headerlink" title="1、安装MySQL"></a>1、安装MySQL</h5><ol><li><p>拉取MySQL5.6版本<br><code>docker pull mysql:5.6</code></p></li><li><p>创建并启动一个容器<br><code>docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=xy123456 --name test_mysql mysql:5.6</code></p><a id="more"></a></li><li><p>进入到mysql容器后,我们通过创建一个远程可以访问的用户,这样我们就能从别的主机访问到我们的数据库了。<br>(注:容器中默认是没有vim的,所以我们首先要安装vim,需要注意的是安装前记得先执行apt-get update命令,不然安装会出现问题。)<br><code>docker exec -it test_mysql /bin/bash</code></p></li></ol><blockquote></blockquote><figure class="highlight plain"><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">>mysql -uroot -p "xy123456"</span><br><span class="line">>create database test;</span><br><span class="line">>grant all privileges on test.* to 'test'@'%' identified by '123456';</span><br><span class="line">>grant all privileges on *.* to 'root'@'%';</span><br><span class="line">>exit;</span><br></pre></td></tr></table></figure><h5 id="2、安装PHP"><a href="#2、安装PHP" class="headerlink" title="2、安装PHP"></a>2、安装PHP</h5><ol><li><p>拉取PHP版本<br><code>docker pull php:7.0-fpm</code></p></li><li><p>创建一个phpfpm容器<br><code>docker run -d -v $PWD/nginx/www/html:/var/www/html -p 9001:9000 --link test_mysql:mysql --name test_phpfpm php:7.0-fpm</code></p></li><li><p>进入容器中,并在 /var/www/html 下新建一个 index.php文件;查看宿主机中的 ./nginx/www/html下是否也有 index.php</p></li><li><p>在容器中,需要安装<code>pdo_mysql</code>模块,在docker容器中可以这样来安装<br><code>docker-php-ext-install pdo_mysql</code><br>然后,通过命令 <code>php -m</code> 查看我们的PHP所有模块(后面会用到PDO来测试数据库的连通性)。</p></li></ol><h5 id="3、安装Nginx"><a href="#3、安装Nginx" class="headerlink" title="3、安装Nginx"></a>3、安装Nginx</h5><ol><li><p>拉取Nginx版本<br><code>docker pull nginx:1.10.3</code></p></li><li><p>创建一个Nginx容器<br><code>docker run -d -p 8080:80 --name test_nginx -v $PWD/nginx/www/html:/var/www/html --link test_phpfpm:phpfpm nginx:1.10.3</code></p></li><li><p>进入容器中</p><figure class="highlight plain"><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">apt-get update</span><br><span class="line">apt-get install -y vim</span><br><span class="line">apt-get install -y net-tools</span><br></pre></td></tr></table></figure></li></ol><p>再容器里找到nginx的配置文件,并修改如下:<br><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">location ~ \.php$ {</span><br><span class="line"> root /var/www/html;</span><br><span class="line"> fastcgi_index index.php;</span><br><span class="line"> fastcgi_pass phpfpm:9000;//这里改成我们之前--link进来的容器,也可以直接用php容器的ip</span><br><span class="line"> fastcgi_param SCRIPT_FILENAME $document_root$fastcdi_script_name;//如果你的根目录和php容器的根目录不一样,这里的$document_root需要换成你php下的根目录,不然php就找不到文件了</span><br><span class="line"> include fastcgi_params;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p><strong>(注:docker容器中服务修改配置,需要重新启动,才能生效。)</strong></p><h5 id="4、测试连通性"><a href="#4、测试连通性" class="headerlink" title="4、测试连通性"></a>4、测试连通性</h5><ol><li>直接访问nginx,检测nginx端口是否映射成功。(失败可在容器中查看nginx日志。)</li><li>访问php文件,检测nginx与php的连通性。(失败可查看容器日志,<code>docker logs container_id -f</code>)</li><li>通过php文件操作数据库,检测nginx、php与mysql的连通性。</li></ol><p>检测代码:<br><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line"><?php</span><br><span class="line">try {</span><br><span class="line"> $con = new PDO('mysql:host=mysql;dbname=test', 'xuye', 'xy123456');</span><br><span class="line"> $con->query('SET NAMES UTF8');</span><br><span class="line"> $res = $con->query('select * from test');</span><br><span class="line"> while ($row = $res->fetch(PDO::FETCH_ASSOC)) {</span><br><span class="line"> echo "id:{$row['id']} name:{$row['name']}";</span><br><span class="line"> }</span><br><span class="line">} catch (PDOException $e) {</span><br><span class="line"> echo '错误原因:' . $e->getMessage();</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>总结说明:</p><ol><li>同一个host下容器之间通信,由于现在的版本,只要默认生成的容器,都会加入到Docker默认的docker0网络下。相互之间可通信。(缺点:相同端口的容器只可开启一个容器。)</li><li>承接上面,在生成容器的时候,可不添加 –link仍可相互通信。(已验证。–link可更改容器中使用的容器名称)</li></ol><p><strong>常用命令特殊安装:</strong></p><table><thead><tr><th>安装命令</th><th>安装包</th><th>命令</th></tr></thead><tbody><tr><td>ps</td><td>procps</td><td>apt-get install -y procps</td></tr><tr><td>netstat</td><td>net-tools</td><td>apt-get install -y net-tools</td></tr><tr><td>ping</td><td>inetutils-ping</td><td>apt-get install inetutils-ping</td></tr></tbody></table>]]></content>
<summary type="html">
<p>参考博客:<a href="https://blog.csdn.net/xy752068432/article/details/75975065" target="_blank" rel="noopener">传送门</a></p>
<h5 id="1、安装MySQL"><a href="#1、安装MySQL" class="headerlink" title="1、安装MySQL"></a>1、安装MySQL</h5><ol>
<li><p>拉取MySQL5.6版本<br><code>docker pull mysql:5.6</code></p>
</li>
<li><p>创建并启动一个容器<br><code>docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=xy123456 --name test_mysql mysql:5.6</code></p>
</summary>
<category term="Docker" scheme="http://yoursite.com/categories/Docker/"/>
<category term="Docker" scheme="http://yoursite.com/tags/Docker/"/>
</entry>
<entry>
<title>Docker之容器间通信</title>
<link href="http://yoursite.com/2018/09/30/Docker%E4%B9%8B%E5%AE%B9%E5%99%A8%E9%97%B4%E9%80%9A%E4%BF%A1/"/>
<id>http://yoursite.com/2018/09/30/Docker之容器间通信/</id>
<published>2018-09-30T04:00:38.000Z</published>
<updated>2018-09-30T04:08:03.837Z</updated>
<content type="html"><![CDATA[<p>容器之间可通过 IP,Docker DNS Server 或 joined 容器三种方式通信。</p><h4 id="IP-通信"><a href="#IP-通信" class="headerlink" title="IP 通信"></a>IP 通信</h4><p>两个容器要能通信,必须要有属于同一个网络的网卡。<br>满足这个条件后,容器就可以通过 IP 交互了。具体做法是在容器创建时通过 –network 指定相应的网络,或者通过 docker network connect 将现有容器加入到指定网络。<br><a id="more"></a></p><h4 id="Docker-DNS-Server"><a href="#Docker-DNS-Server" class="headerlink" title="Docker DNS Server"></a>Docker DNS Server</h4><p>通过 IP 访问容器虽然满足了通信的需求,但还是不够灵活。因为我们在部署应用之前可能无法确定 IP,部署之后再指定要访问的 IP 会比较麻烦。对于这个问题,可以通过 docker 自带的 DNS 服务解决。</p><p>从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过“容器名”通信。方法很简单,只要在启动时用 –name 为容器命名就可以了。</p><p>下面启动两个容器 bbox1 和 bbox2:<br><figure class="highlight plain"><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">docker run -it --network=my_net2 --name=bbox1 busybox</span><br><span class="line">docker run -it --network=my_net2 --name=bbox2 busybox</span><br></pre></td></tr></table></figure></p><p>然后,bbox2 就可以直接 ping 到 bbox1 了:<br><img src="/uploads/2018/09/docker-network-communication-01.jpg" alt=""></p><p>使用 docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。下面验证一下:<br>创建 bbox3 和 bbox4,均连接到 bridge 网络。<br><figure class="highlight plain"><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">docker run -it --name=bbox3 busybox</span><br><span class="line">docker run -it --name=bbox4 busybox</span><br></pre></td></tr></table></figure></p><p>bbox4 无法 ping 到 bbox3。<br><img src="/uploads/2018/09/docker-network-communication-02.jpg" alt=""></p><h4 id="joined-容器"><a href="#joined-容器" class="headerlink" title="joined 容器"></a>joined 容器</h4><p>joined 容器是另一种实现容器间通信的方式。<br>joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。请看下面的例子:</p><p>先创建一个 httpd 容器,名字为 web1。<br><code>docker run -d -it --name=web1 httpd</code><br>然后创建 busybox 容器并通过 <code>--network=container:web1</code> 指定 jointed 容器为 web1:<br><img src="/uploads/2018/09/docker-network-communication-03.jpg" alt=""></p><p>请注意 busybox 容器中的网络配置信息,下面我们查看一下 web1 的网络:<br><img src="/uploads/2018/09/docker-network-communication-04.jpg" alt=""></p><p>看!busybox 和 web1 的网卡 mac 地址与 IP 完全一样,它们共享了相同的网络栈。busybox 可以直接用 127.0.0.1 访问 web1 的 http 服务。<br><img src="/uploads/2018/09/docker-network-communication-05.jpg" alt=""></p><p>joined 容器非常适合以下场景:</p><ol><li>不同容器中的程序希望通过 loopback 高效快速地通信,比如 web server 与 app server。</li><li>希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。</li></ol><p>容器之间的通信我们已经搞清楚了,接下来要考虑的是容器如何与外部世界通信?</p><h4 id="容器如何访问到外部世界?"><a href="#容器如何访问到外部世界?" class="headerlink" title="容器如何访问到外部世界?"></a>容器如何访问到外部世界?</h4><p><strong>容器默认就能访问外网。</strong><br>详细信息查看博客:<a href="https://www.cnblogs.com/CloudMan6/p/7107407.html" target="_blank" rel="noopener">传送门</a></p><h4 id="外部世界如何访问容器?"><a href="#外部世界如何访问容器?" class="headerlink" title="外部世界如何访问容器?"></a>外部世界如何访问容器?</h4><p>答案是:<strong>端口映射。</strong></p><p>docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。容器启动时通过-p参数映射端口:<br><img src="/uploads/2018/09/docker-network-communication-06.jpg" alt=""></p><p>容器启动后,可通过 docker ps 或者 docker port 查看到 host 映射的端口。在上面的例子中,httpd 容器的 80 端口被映射到 host 32773 上,这样就可以通过 <code><host ip>:<32773></code> 访问容器的 web 服务了。<br><img src="/uploads/2018/09/docker-network-communication-07.jpg" alt=""></p><p>除了映射动态端口,也可在 -p 中指定映射到 host 某个特定端口,例如可将 80 端口映射到 host 的 8080 端口:<br><img src="/uploads/2018/09/docker-network-communication-08.jpg" alt=""></p><p>每一个映射的端口,host 都会启动一个 docker-proxy 进程来处理访问容器的流量:<br><img src="/uploads/2018/09/docker-network-communication-09.jpg" alt=""></p><p>以 0.0.0.0:32773->80/tcp 为例分析整个过程:<br><img src="/uploads/2018/09/docker-network-communication-10.jpg" alt=""></p><ol><li>docker-proxy 监听 host 的 32773 端口。</li><li>当 curl 访问 10.0.2.15:32773 时,docker-proxy 转发给容器 172.17.0.2:80。</li><li>httpd 容器响应请求并返回结果。</li></ol>]]></content>
<summary type="html">
<p>容器之间可通过 IP,Docker DNS Server 或 joined 容器三种方式通信。</p>
<h4 id="IP-通信"><a href="#IP-通信" class="headerlink" title="IP 通信"></a>IP 通信</h4><p>两个容器要能通信,必须要有属于同一个网络的网卡。<br>满足这个条件后,容器就可以通过 IP 交互了。具体做法是在容器创建时通过 –network 指定相应的网络,或者通过 docker network connect 将现有容器加入到指定网络。<br>
</summary>
<category term="Docker" scheme="http://yoursite.com/categories/Docker/"/>
<category term="Docker" scheme="http://yoursite.com/tags/Docker/"/>
</entry>
<entry>
<title>Docker之容器网络解析</title>
<link href="http://yoursite.com/2018/09/30/Docker%E4%B9%8B%E5%AE%B9%E5%99%A8%E7%BD%91%E7%BB%9C%E8%A7%A3%E6%9E%90/"/>
<id>http://yoursite.com/2018/09/30/Docker之容器网络解析/</id>
<published>2018-09-30T04:00:17.000Z</published>
<updated>2018-09-30T04:09:21.285Z</updated>
<content type="html"><![CDATA[<h4 id="一、Docker原生网络"><a href="#一、Docker原生网络" class="headerlink" title="一、Docker原生网络"></a>一、Docker原生网络</h4><p>Docker 网络从覆盖范围可分为单个 host 上的容器网络和跨多个 host 的网络。</p><h5 id="1、单个-host-上的容器网络"><a href="#1、单个-host-上的容器网络" class="headerlink" title="1、单个 host 上的容器网络"></a>1、单个 host 上的容器网络</h5><p>Docker 安装时会自动在 host 上创建三个网络,我们可用 docker network ls 命令查看:<br><img src="/uploads/2018/09/docker-network-01.jpg" alt=""><br><a id="more"></a></p><h6 id="(1)none-网络"><a href="#(1)none-网络" class="headerlink" title="(1)none 网络"></a>(1)none 网络</h6><p>故名思议,none 网络就是什么都没有的网络。挂在这个网络下的容器除了 lo,没有其他任何网卡。容器创建时,可以通过 –network=none 指定使用 none 网络。<br><img src="/uploads/2018/09/docker-network-none.jpg" alt=""></p><p>我们不禁会问,这样一个封闭的网络有什么用呢?<br>其实还真有应用场景。封闭意味着隔离,一些对安全性要求高并且不需要联网的应用可以使用 none 网络。<br>比如某个容器的唯一用途是生成随机密码,就可以放到 none 网络中避免密码被窃取。</p><h6 id="(2)host-网络"><a href="#(2)host-网络" class="headerlink" title="(2)host 网络"></a>(2)host 网络</h6><p>连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。可以通过 –network=host 指定使用 host 网络。<br><img src="/uploads/2018/09/docker-network-host.jpg" alt=""></p><p>在容器中可以看到 host 的所有网卡,并且连 hostname 也是 host 的。host 网络的使用场景又是什么呢?<br>直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host 上已经使用的端口就不能再用了。</p><p>Docker host 的另一个用途是让容器可以直接配置 host 网路。比如某些跨 host 的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置,比如管理 iptables。</p><h6 id="(3)bridge-网络"><a href="#(3)bridge-网络" class="headerlink" title="(3)bridge 网络"></a>(3)bridge 网络</h6><p>应用最广泛也是默认的 bridge 网络。<br>Docker 安装时会创建一个 命名为 docker0 的 linux bridge。如果不指定–network,创建的容器默认都会挂到 docker0 上。<br><img src="/uploads/2018/09/docker-network-02.jpg" alt=""></p><blockquote><p>使用brctl命令,需要安装</p></blockquote><p>当前 docker0 上没有任何其他网络设备,我们创建一个容器看看有什么变化。<br><img src="/uploads/2018/09/docker-network-03.jpg" alt=""><br>一个新的网络接口 veth28c57df 被挂到了 docker0 上,veth28c57df就是新创建容器的虚拟网卡。</p><p>下面看一下容器的网络配置。<br><img src="/uploads/2018/09/docker-network-04.jpg" alt=""><br>容器有一个网卡 eth0@if34。大家可能会问了,为什么不是veth28c57df 呢?</p><p>实际上 eth0@if34 和 veth28c57df 是一对 veth pair。veth pair 是一种成对出现的特殊网络设备,可以把它们想象成由一根虚拟网线连接起来的一对网卡,网卡的一头(eth0@if34)在容器中,另一头(veth28c57df)挂在网桥 docker0 上,其效果就是将 eth0@if34 也挂在了 docker0 上。</p><p>我们还看到 eth0@if34 已经配置了 IP 172.17.0.2,为什么是这个网段呢?让我们通过 docker network inspect bridge 看一下 bridge 网络的配置信息:<br><img src="/uploads/2018/09/docker-network-05.jpg" alt=""></p><p>原来 bridge 网络配置的 subnet 就是 172.17.0.0/16,并且网关是 172.17.0.1。这个网关在哪儿呢?大概你已经猜出来了,就是 docker0。<br><img src="/uploads/2018/09/docker-network-06.jpg" alt=""></p><p>当前容器网络拓扑结构如图所示:<br><img src="/uploads/2018/09/docker-network-07.jpg" alt=""><br>容器创建时,docker 会自动从 172.17.0.0/16 中分配一个 IP,这里 16 位的掩码保证有足够多的 IP 可以供容器使用。</p><h5 id="2、跨多个-host-的网络"><a href="#2、跨多个-host-的网络" class="headerlink" title="2、跨多个 host 的网络"></a>2、跨多个 host 的网络</h5><p>待补充…</p><h4 id="二、自定义网络"><a href="#二、自定义网络" class="headerlink" title="二、自定义网络"></a>二、自定义网络</h4><p>除了 none, host, bridge 这三个自动创建的网络,用户也可以根据业务需要创建 user-defined 网络。</p><p>Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。overlay 和 macvlan 用于创建跨主机的网络。</p><p>我们可通过 bridge 驱动创建类似前面默认的 bridge 网络,例如<br><img src="/uploads/2018/09/docker-network-bridge-01.jpg" alt=""></p><p>查看一下当前 host 的网络结构变化:<br><img src="/uploads/2018/09/docker-network-bridge-02.jpg" alt=""></p><p>新增了一个网桥 br-eaed97dc9a77,这里 eaed97dc9a77 正好新建 bridge 网络 my_net 的短 id。执行 docker network inspect 查看一下 my_net 的配置信息:<br><img src="/uploads/2018/09/docker-network-bridge-03.jpg" alt=""></p><p>这里 172.18.0.0/16 是 Docker 自动分配的 IP 网段。</p><p>我们可以自己指定 IP 网段吗?<br>答案是:可以。</p><p>只需在创建网段时指定 –subnet 和 –gateway 参数:<br><img src="/uploads/2018/09/docker-network-bridge-04.jpg" alt=""></p><p>这里我们创建了新的 bridge 网络 my_net2,网段为 172.22.16.0/24,网关为 172.22.16.1。与前面一样,网关在 my_net2 对应的网桥 br-5d863e9f78b6 上:<br><img src="/uploads/2018/09/docker-network-bridge-05.jpg" alt=""></p><p>容器要使用新的网络,需要在启动时通过 –network 指定:<br><img src="/uploads/2018/09/docker-network-bridge-06.jpg" alt=""></p><p>容器分配到的 IP 为 172.22.16.2。</p><p>到目前为止,容器的 IP 都是 docker 自动从 subnet 中分配,我们能否指定一个静态 IP 呢?</p><p>答案是:可以,通过–ip指定。<br><img src="/uploads/2018/09/docker-network-bridge-07.jpg" alt=""><br>注:<strong>只有使用 –subnet 创建的网络才能指定静态 IP。</strong></p><p>my_net 创建时没有指定 –subnet,如果指定静态 IP 报错如下:<br><img src="/uploads/2018/09/docker-network-bridge-08.jpg" alt=""></p><p>好了,我们来看看当前 docker host 的网络拓扑结构。<br><img src="/uploads/2018/09/docker-network-bridge-09.jpg" alt=""></p><h4 id="三、理解容器之间的连通性"><a href="#三、理解容器之间的连通性" class="headerlink" title="三、理解容器之间的连通性"></a>三、理解容器之间的连通性</h4><p>通过上面的实践,当前 docker host 的网络拓扑结构如下图所示<br><img src="/uploads/2018/09/docker-network-bridge-10.jpg" alt=""></p><p>两个 busybox 容器都挂在 my_net2 上,应该能够互通,我们验证一下:<br><img src="/uploads/2018/09/docker-network-bridge-11.jpg" alt=""><br>可见同一网络中的容器、网关之间都是可以通信的。</p><p>my_net2 与默认 bridge 网络能通信吗?</p><p>从拓扑图可知,两个网络属于不同的网桥,应该不能通信,我们通过实验验证一下,让 busybox 容器 ping httpd 容器:<br><img src="/uploads/2018/09/docker-network-bridge-12.jpg" alt=""><br>确实 ping 不通,符合预期。</p><p>原因:<strong>iptables DROP 掉了网桥 docker0 与 br-5d863e9f78b6 之间双向的流量。</strong><br>从规则的命名 DOCKER-ISOLATION 可知 docker 在设计上就是要隔离不同的 netwrok。</p><p>那么接下来的问题是:怎样才能让 busybox 与 httpd 通信呢?<br>答案是:为 httpd 容器添加一块 net_my2 的网卡。这个可以通过docker network connect 命令实现。</p><p><img src="/uploads/2018/09/docker-network-bridge-13.jpg" alt=""></p><p>我们在 httpd 容器中查看一下网络配置:<br><img src="/uploads/2018/09/docker-network-bridge-14.jpg" alt=""></p><p>容器中增加了一个网卡 eth1,分配了 my_net2 的 IP 172.22.16.3。现在 busybox 应该能够访问 httpd 了,验证一下:<br><img src="/uploads/2018/09/docker-network-bridge-15.jpg" alt=""></p><p>busybox 能够 ping 到 httpd,并且可以访问 httpd 的 web 服务。当前网络结构如图所示:<br><img src="/uploads/2018/09/docker-network-bridge-16.jpg" alt=""></p>]]></content>
<summary type="html">
<h4 id="一、Docker原生网络"><a href="#一、Docker原生网络" class="headerlink" title="一、Docker原生网络"></a>一、Docker原生网络</h4><p>Docker 网络从覆盖范围可分为单个 host 上的容器网络和跨多个 host 的网络。</p>
<h5 id="1、单个-host-上的容器网络"><a href="#1、单个-host-上的容器网络" class="headerlink" title="1、单个 host 上的容器网络"></a>1、单个 host 上的容器网络</h5><p>Docker 安装时会自动在 host 上创建三个网络,我们可用 docker network ls 命令查看:<br><img src="/uploads/2018/09/docker-network-01.jpg" alt=""><br>
</summary>
<category term="Docker" scheme="http://yoursite.com/categories/Docker/"/>
<category term="Docker" scheme="http://yoursite.com/tags/Docker/"/>
</entry>
<entry>
<title>Docker之问题集锦</title>
<link href="http://yoursite.com/2018/09/29/Docker%E4%B9%8B%E9%97%AE%E9%A2%98%E9%9B%86%E9%94%A6/"/>
<id>http://yoursite.com/2018/09/29/Docker之问题集锦/</id>
<published>2018-09-29T09:26:13.000Z</published>
<updated>2018-09-29T09:26:57.481Z</updated>
<content type="html"><![CDATA[<h4 id="一、WINDOWS下错误集锦"><a href="#一、WINDOWS下错误集锦" class="headerlink" title="一、WINDOWS下错误集锦"></a>一、WINDOWS下错误集锦</h4><h5 id="问题一"><a href="#问题一" class="headerlink" title="问题一"></a>问题一</h5><p>解决 Docker pull 出现的net/http: TLS handshake timeout 的一个办法</p><p>解决思路:百度搜了下net/http: TLS handshake timeout</p><p>出现一个这个结果比较满意<br><code>http://dockone.io/article/876?utm_source=tuicool&utm_medium=referral</code><br>我不用官方的dockhub了,转而使用国内的仓库daocloud<br><figure class="highlight plain"><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">$ echo "DOCKER_OPTS=\"\$DOCKER_OPTS --registry-mirror=http://f2d6cb40.m.daocloud.io\"" | sudo tee -a /etc/default/docker</span><br><span class="line">$ sudo service docker restart</span><br></pre></td></tr></table></figure></p><p>重启docker服务后,再次pull 就 ok了<br><a id="more"></a></p><h5 id="问题二"><a href="#问题二" class="headerlink" title="问题二"></a>问题二</h5><p>运行Dockerfile启动容器的时候报错,如下:<br><code>docker: executable file not found in $PATH</code></p><p>问题出现的原因:<br>主要原因是docker 执行的时候没有找到对应的Dockerfile文件位置。</p><p>解决方法:<br>在执行<code>docker run</code>的时候,要指定Dockerfile的运行目录位置。如果DOckerfile在当前目录,则在命令后添加“.”即可。(必须项,否则会报此错误。)</p><h5 id="问题三"><a href="#问题三" class="headerlink" title="问题三"></a>问题三</h5><p>在Windows家庭版下安装了docker,并尝试在其中运行jupyter notebook等服务,但映射完毕之后,在主机的浏览器中,打开localhost:port无法访问对应的服务。</p><p>问题出现的原因:</p><blockquote><p>The reason you’re having this, is because on Linux, the docker daemon (and your containers) run on the Linux machine itself, so “localhost” is also the host that the container is running on, and the ports are mapped to.<br>On Windows (and OS X), the docker daemon, and your containers cannot run natively, so only the docker client is running on your Windows machine, but the daemon (and your containers) run in a VirtualBox Virtual Machine, that runs Linux.</p><p>因为docker是运行在Linux上的,在Windows中运行docker,实际上还是在Windows下先安装了一个Linux环境,然后在这个系统中运行的docker。也就是说,服务中使用的localhost指的是这个Linux环境的地址,而不是我们的宿主环境Windows。</p></blockquote><p>解决方法:<br>通过命令 <code>docker-machine ip default</code><br>其中,default 是docker-machine的name,可以通过<code>docker-machine -ls</code> 查看<br>找到这个Linux的ip地址,一般情况下这个地址是192.168.99.100,然后在Windows的浏览器中,输入这个地址,加上服务的端口即可启用了。<br>(<a href="https://www.cnblogs.com/hypnus-ly/p/8683215.html" target="_blank" rel="noopener">参考博客</a>)</p>]]></content>
<summary type="html">
<h4 id="一、WINDOWS下错误集锦"><a href="#一、WINDOWS下错误集锦" class="headerlink" title="一、WINDOWS下错误集锦"></a>一、WINDOWS下错误集锦</h4><h5 id="问题一"><a href="#问题一" class="headerlink" title="问题一"></a>问题一</h5><p>解决 Docker pull 出现的net/http: TLS handshake timeout 的一个办法</p>
<p>解决思路:百度搜了下net/http: TLS handshake timeout</p>
<p>出现一个这个结果比较满意<br><code>http://dockone.io/article/876?utm_source=tuicool&amp;utm_medium=referral</code><br>我不用官方的dockhub了,转而使用国内的仓库daocloud<br><figure class="highlight plain"><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">$ echo &quot;DOCKER_OPTS=\&quot;\$DOCKER_OPTS --registry-mirror=http://f2d6cb40.m.daocloud.io\&quot;&quot; | sudo tee -a /etc/default/docker</span><br><span class="line">$ sudo service docker restart</span><br></pre></td></tr></table></figure></p>
<p>重启docker服务后,再次pull 就 ok了<br>
</summary>
<category term="Docker" scheme="http://yoursite.com/categories/Docker/"/>
<category term="Docker" scheme="http://yoursite.com/tags/Docker/"/>
</entry>
<entry>
<title>Docker之Dockerfile详解</title>
<link href="http://yoursite.com/2018/09/28/Docker%E4%B9%8BDockerfile%E8%AF%A6%E8%A7%A3/"/>
<id>http://yoursite.com/2018/09/28/Docker之Dockerfile详解/</id>
<published>2018-09-28T09:43:38.000Z</published>
<updated>2018-09-29T09:23:50.149Z</updated>
<content type="html"><![CDATA[<h4 id="一、Dockerfile详解"><a href="#一、Dockerfile详解" class="headerlink" title="一、Dockerfile详解"></a>一、Dockerfile详解</h4><h5 id="(1)Dockerfile包含的信息"><a href="#(1)Dockerfile包含的信息" class="headerlink" title="(1)Dockerfile包含的信息"></a>(1)Dockerfile包含的信息</h5><ul><li>基础镜像信息 </li><li>维护者信息 </li><li>镜像操作指令 </li><li>容器启动时执行指令<a id="more"></a><h5 id="(2)文件的编写"><a href="#(2)文件的编写" class="headerlink" title="(2)文件的编写"></a>(2)文件的编写</h5><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line"># This is docker file</span><br><span class="line"># version v1</span><br><span class="line"># Author wangshibo</span><br><span class="line"># Base image(基础镜像)</span><br><span class="line">FROM centos</span><br><span class="line"></span><br><span class="line"># Maintainer(维护者信息)</span><br><span class="line">MAINTAINER wangshibo 2134728394@qq.com</span><br><span class="line"></span><br><span class="line"># Commands(执行命令)</span><br><span class="line">RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm</span><br><span class="line">RUN yum -y install nginx</span><br><span class="line"># Add(添加文件)</span><br><span class="line">ADD index.html /usr/share/nginx/html/index.html # index.html是自己编写的文件,放在后面的目录中,因为yum安装后Documentroot是在这里</span><br><span class="line">RUN echo "daemon off;" >>/etc/nginx/nginx.conf</span><br><span class="line">EXPOSE 80 # 对外的端口</span><br><span class="line">CMD ['nginx'] # 执行的命令</span><br></pre></td></tr></table></figure></li></ul><p><img src="./images/docker-dockerfile.png" alt=""></p><h5 id="(3)构建容器,并运行"><a href="#(3)构建容器,并运行" class="headerlink" title="(3)构建容器,并运行"></a>(3)构建容器,并运行</h5><blockquote><p>建立newnginx容器,-t:标签,执行/opt/dockerfile/nginx/下面的默认的Dockerfile文件<br><figure class="highlight plain"><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">[root@linux-node2 nginx]# docker build -t cgt/mynginx:v3 /opt/dockerfile/nginx/</span><br><span class="line">[root@linux-node2 nginx]# docker run -d -p 83:80 cgt/mynginx:v3</span><br></pre></td></tr></table></figure></p></blockquote><h4 id="二、指令说明"><a href="#二、指令说明" class="headerlink" title="二、指令说明"></a>二、指令说明</h4><table><thead><tr><th>指令</th><th>说明</th></tr></thead><tbody><tr><td>FROM</td><td>指定所创建镜像的基础镜像</td></tr><tr><td>MAINTAINER</td><td>指定维护者信息</td></tr><tr><td>RUN</td><td>运行命令</td></tr><tr><td>CMD</td><td>指定启动容器时默认执行的命令</td></tr><tr><td>LABEL</td><td>指定生成镜像的元数据标签信息</td></tr><tr><td>EXPOSE</td><td>声明镜像内服务所监听的端口</td></tr><tr><td>ENV</td><td>指定环境变量</td></tr><tr><td>ADD</td><td>赋值指定的<code><src></code>路径下的内容到容器中的<code><dest></code>路径下,<code><src></code>可以为URL;如果为tar文件,会自动解压到<code><dest></code>路径下</td></tr><tr><td>COPY</td><td>赋值本地主机的<code><src></code>路径下的内容到容器中的<code><dest></code>路径下;一般情况下推荐使用COPY而不是ADD</td></tr><tr><td>ENTRYPOINT</td><td>指定镜像的默认入口</td></tr><tr><td>VOLUME</td><td>创建数据挂载点</td></tr><tr><td>USER</td><td>指定运行容器时的用户名或UID</td></tr><tr><td>WORKDIR</td><td>配置工作目录</td></tr><tr><td>ARG</td><td>指定镜像内使用的参数(例如版本号信息等)</td></tr><tr><td>ONBUILD</td><td>配置当前所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作的命令</td></tr><tr><td>STOPSIGNAL</td><td>容器退出的信号</td></tr><tr><td>HEALTHCHECK</td><td>如何进行健康检查</td></tr><tr><td>SHELL</td><td>指定使用SHELL时的默认SHELL类型</td></tr></tbody></table><h5 id="1-FROM"><a href="#1-FROM" class="headerlink" title="1. FROM"></a>1. FROM</h5><p>指定所创建的镜像的基础镜像,如果本地不存在,则默认会去Docker Hub下载指定镜像。<br>格式为:<br><code>FROM <image></code>,或<code>FROM <image>:<tag></code>,或<code>FROM <image>@<digest></code><br>任何Dockerfile中的第一条指令必须为FROM指令。并且,如果在同一个Dockerfile文件中创建多个镜像,可以使用多个FROM指令(每个镜像一次)。</p><h5 id="2-MAINTAINER"><a href="#2-MAINTAINER" class="headerlink" title="2. MAINTAINER"></a>2. MAINTAINER</h5><p>指定维护者信息。<br>格式为:<br><code>MAINTAINER <name></code><br>例如:<br>MAINTAINER <a href="mailto:image_creator@docker.com" target="_blank" rel="noopener">image_creator@docker.com</a><br>该信息将会写入生成镜像的Author属性域中。</p><h5 id="3-RUN"><a href="#3-RUN" class="headerlink" title="3. RUN"></a>3. RUN</h5><p>运行指定命令。<br>格式为:<br><code>RUN <command></code> 或 <code>RUN ["executable", "param1", "param2"]</code></p><font color="red">注意:后一个指令会被解析为json数组,所以必须使用双引号。</font><br>前者默认将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行,不会启动shell环境。<br>指定使用其他终端类型可以通过第二种方式实现,例如:<br><code>RUN ["/bin/bash", "-c", "echo hello"]</code><br>每条RUN指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用\换行。例如:<br><figure class="highlight plain"><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">RUN apt-get update \</span><br><span class="line"> && apt-get install -y libsnappy-dev zliblg-dev libbz2-dev \</span><br><span class="line"> && rm -rf /var/cache/apt</span><br></pre></td></tr></table></figure><br><br>##### 4. CMD #####<br>CMD指令用来指定启动容器时默认执行的命令。它支持三种格式:<br>1. <code>CMD ["executable", "param1", "param2"]</code> 使用exec执行,是推荐使用的方式;<br>2. <code>CMD param1 param2</code> 在/bin/sh中执行,提供给需要交互的应用;<br>3. <code>CMD ["param1", "param2"]</code> 提供给ENTRYPOINT的默认参数。<br><br>每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时指定了运行的命令(作为run的参数),则会覆盖掉CMD指定的命令。<br><br>##### 5. LABEL #####<br>LABEL指令用来生成用于生成镜像的元数据的标签信息。<br>格式为:<code>LABEL <key>=<value> <key>=<value> <key>=<value> ...</code><br>例如:<br><figure class="highlight plain"><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">LABEL version="1.0"</span><br><span class="line">LABEL description="This text illustrates \ that label-values can span multiple lines."</span><br></pre></td></tr></table></figure><br><br>##### 6. EXPOSE #####<br>声明镜像内服务所监听的端口。<br>格式为:<code>EXPOSE <port> [<port>...]</code><br>例如:<br><code>EXPOSE 22 80 443 3306</code><br><font color="red">注意:<br>该命令只是起到声明租用,并不会自动完成端口映射。<br>在容器启动时需要使用-P(大写P),Docker主机会自动分配一个宿主机未被使用的临时端口转发到指定的端口;使用-p(小写p),则可以具体指定哪个宿主机的本地端口映射过来。</font><h5 id="7-ENV"><a href="#7-ENV" class="headerlink" title="7. ENV"></a>7. ENV</h5><p>指定环境变量,在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在。<br>格式为:<code>ENV <key><value>或ENV<key>=<value>...</code><br>例如:<br><figure class="highlight plain"><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">ENV GOLANG_VERSION 1.6.3</span><br><span class="line">ENV GOLANG_DOWNLOAD_RUL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz</span><br><span class="line">ENV GOLANG_DOWNLOAD_SHA256 cdd5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd7561275a87aeb</span><br><span class="line"></span><br><span class="line">RUN curl -fssL "$GOLANG_DOWNLOAD_RUL" -o golang.tar.gz && echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && tar -C /usr/local -xzf golang.tar.gz && rm golang.tar.gz</span><br><span class="line"></span><br><span class="line">ENV GOPATH $GOPATH/bin:/usr/local/go/bin:$PATH</span><br><span class="line"></span><br><span class="line">RUN mkdir -p "$GOPATH/bin" && chmod -R 777 "$GOPATH"</span><br></pre></td></tr></table></figure></p><p>指令指定的环境变量在运行时可以被覆盖掉,如<code>docker run --env <key>=<value> built_image</code>。</p><h5 id="8-ADD"><a href="#8-ADD" class="headerlink" title="8. ADD"></a>8. ADD</h5><p>该指令将复制指定的<src>路径下的内容到容器中的<dest>路径下。<br>格式为:<code>ADD<src> <dest></code><br>其中<code><src></code>可以使Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL,还可以是一个tar文件(如果是tar文件,会自动解压到<code><dest></code>路径下)。<code><dest></code>可以使镜像内的绝对路径,或者相当于工作目录(WORKDIR)的相对路径。路径支持正则表达式,例如:<br><code>ADD *.c /code/</code></dest></src></p><h5 id="9-COPY"><a href="#9-COPY" class="headerlink" title="9. COPY"></a>9. COPY</h5><p>复制本地主机的<code><src></code>(为Dockerfile所在目录的一个相对路径、文件或目录)下的内容到镜像中的<code><dest></code>下。目标路径不存在时,会自动创建。路径同样支持正则。<br>格式为:<code>COPY <src> <dest></code><br>当使用本地目录为源目录时,推荐使用COPY。</p><h5 id="10-ENTRYPOINT"><a href="#10-ENTRYPOINT" class="headerlink" title="10. ENTRYPOINT"></a>10. ENTRYPOINT</h5><p>指定镜像的默认入口命令,该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。<br>支持两种格式:</p><ol><li><code>ENTRYPOINT ["executable","param1","param2"]</code> (exec调用执行);</li><li><code>ENTRYPOINT command param1 param2</code>(shell中执行)。</li></ol><p>此时,CMD指令指定值将作为根命令的参数。<br>每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个有效。<br>在运行时可以被<code>--entrypoint</code>参数覆盖掉,如<code>docker run --entrypoint</code>。</p><h5 id="11-VOLUME"><a href="#11-VOLUME" class="headerlink" title="11. VOLUME"></a>11. VOLUME</h5><p>创建一个数据卷挂载点。<br>格式为:<code>VOLUME ["/data"]</code><br>可以从本地主机或者其他容器挂载数据卷,一般用来存放数据库和需要保存的数据等。</p><h5 id="12-USER"><a href="#12-USER" class="headerlink" title="12. USER"></a>12. USER</h5><p>指定运行容器时的用户名或UID,后续的RUN等指令也会使用特定的用户身份。<br>格式为:<code>USER daemon</code><br>当服务不需要管理员权限时,可以通过该指令指定运行用户,并且可以在之前创建所需要的用户。例如:<br><code>RUN groupadd -r nginx && useradd -r -g nginx nginx</code><br>要临时获取管理员权限可以用gosu或者sudo。</p><h5 id="13-WORKDIR"><a href="#13-WORKDIR" class="headerlink" title="13. WORKDIR"></a>13. WORKDIR</h5><p>为后续的RUN、CMD和ENTRYPOINT指令配置工作目录。<br>格式为:<code>WORKDIR /path/to/workdir</code><br>可以使用多个WORKDIR指令,后续命令如果参数是相对的,则会基于之前命令指定的路径。例如:<br><figure class="highlight plain"><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">WORKDIR /a</span><br><span class="line">WORKDIR b</span><br><span class="line">WORKDIR c</span><br><span class="line">RUN pwd</span><br></pre></td></tr></table></figure></p><p>则最终路径为/a/b/c</p><h5 id="14-ARG"><a href="#14-ARG" class="headerlink" title="14. ARG"></a>14. ARG</h5><p>指定一些镜像内使用的参数(例如版本号信息等),这些参数在执行<code>docker build</code>命令时才以<code>--build-arg<varname>=<value></code>格式传入。<br>格式为:<code>ARG<name>[=<default value>]</code><br>则可以用<code>docker build --build-arg<name>=<value></code>来指定参数值。</p><h5 id="15-ONBUILD"><a href="#15-ONBUILD" class="headerlink" title="15. ONBUILD"></a>15. ONBUILD</h5><p>配置当所创建的镜像作为其他镜像的基础镜像的时候,所执行创建操作指令。<br>格式为:<code>ONBUILD [INSTRUCTION]</code><br>例如Dockerfile使用如下的内容创建了镜像image-A:<br><figure class="highlight plain"><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><br><span class="line">ONBUILD ADD . /app/src</span><br><span class="line">ONBUILD RUN /usr/local/bin/python-build --dir /app/src</span><br><span class="line">[...]</span><br></pre></td></tr></table></figure></p><p>如果基于image-A镜像创建新的镜像时,新的Dockerfile中使用FROM image-A指定基础镜像,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令:<br><figure class="highlight plain"><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">FROM image-A</span><br><span class="line"></span><br><span class="line"># Automatically run the following</span><br><span class="line">ONBUILD ADD . /app/src</span><br><span class="line">ONBUILD RUN /usr/local/bin/python-build --dir /app/src</span><br></pre></td></tr></table></figure></p><p>使用ONBUILD指令的镜像,推荐在标签中注明,例如:<code>ruby:1.9-onbuild</code>。</p><h4 id="三、后记"><a href="#三、后记" class="headerlink" title="三、后记"></a>三、后记</h4><p>从需求出发,定制适合自己需求、高效方便的镜像,可以参考他人优秀的Dockerfile文件,在构建中慢慢优化Dockerfile文件:</p><ol><li>精简镜像用途: 尽量让每个镜像的用途都比较集中、单一,避免构造大而复杂、多功能的镜像;</li><li>选用合适的基础镜像: 过大的基础镜像会造成构建出臃肿的镜像,一般推荐比较小巧的镜像作为基础镜像;</li><li>提供详细的注释和维护者信息: Dockerfile也是一种代码,需要考虑方便后续扩展和他人使用;</li><li>正确使用版本号: 使用明确的具体数字信息的版本号信息,而非latest,可以避免无法确认具体版本号,统一环境;</li><li>减少镜像层数: 减少镜像层数建议尽量合并RUN指令,可以将多条RUN指令的内容通过&&连接;</li><li>及时删除临时和缓存文件: 这样可以避免构造的镜像过于臃肿,并且这些缓存文件并没有实际用途;</li><li>提高生产速度: 合理使用缓存、减少目录下的使用文件,使用.dockeringore文件等;</li><li>调整合理的指令顺序: 在开启缓存的情况下,内容不变的指令尽量放在前面,这样可以提高指令的复用性;</li><li>减少外部源的干扰: 如果确实要从外部引入数据,需要制定持久的地址,并带有版本信息,让他人可以重复使用而不出错。</li><li>不要在容器中存储数据: 容器可能被停止,销毁,或替换。一个运行在容器中的程序版本1.0,应该很容易被1.1的版本替换且不影响或损失数据。有鉴于此,如果你需要存储数据,请存在卷中,并且注意如果两个容器在同一个卷上写数据会导致崩溃。确保你的应用被设计成在共享数据存储上写入。</li><li>不要在镜像中存储凭据。使用环境变量: 不要将镜像中的任何用户名/密码写死。使用环境变量来从容器外部获取此信息。</li><li>使用非root用户运行进程: “docker容器默认以root运行。(…)随着docker的成熟,更多的安全默认选项变得可用。现如今,请求root对于其他人是危险的,可能无法在所有环境中可用。你的镜像应该使用USER指令来指令容器的一个非root用户来运行。”</li><li>不要依赖IP地址: 每个容器都有自己的内部IP地址,如果你启动并停止它地址可能会变化。如果你的应用或微服务需要与其他容器通讯,使用任何命名与(或者)环境变量来从一个容器传递合适信息到另一个。</li></ol><h4 id="附属实例:Nginx(已验证)"><a href="#附属实例:Nginx(已验证)" class="headerlink" title="附属实例:Nginx(已验证)"></a>附属实例:Nginx(已验证)</h4><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">FROM centos</span><br><span class="line"></span><br><span class="line">MAINTAINER 2018-04-011 lipengcheng 777@qq.com</span><br><span class="line"></span><br><span class="line">RUN yum -y install gcc* make pcre-devel zlib-devel</span><br><span class="line"></span><br><span class="line">RUN rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm && yum -y install nginx</span><br><span class="line"></span><br><span class="line">EXPOSE 80</span><br><span class="line"></span><br><span class="line">CMD ["nginx", "-g", "daemon off;"]</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h4 id="一、Dockerfile详解"><a href="#一、Dockerfile详解" class="headerlink" title="一、Dockerfile详解"></a>一、Dockerfile详解</h4><h5 id="(1)Dockerfile包含的信息"><a href="#(1)Dockerfile包含的信息" class="headerlink" title="(1)Dockerfile包含的信息"></a>(1)Dockerfile包含的信息</h5><ul>
<li>基础镜像信息 </li>
<li>维护者信息 </li>
<li>镜像操作指令 </li>
<li>容器启动时执行指令
</summary>
<category term="Docker" scheme="http://yoursite.com/categories/Docker/"/>
<category term="Docker" scheme="http://yoursite.com/tags/Docker/"/>
</entry>
<entry>
<title>Docker之基础篇</title>
<link href="http://yoursite.com/2018/09/28/Docker%E4%B9%8B%E5%9F%BA%E7%A1%80%E7%AF%87/"/>
<id>http://yoursite.com/2018/09/28/Docker之基础篇/</id>
<published>2018-09-28T08:32:51.000Z</published>
<updated>2018-09-29T09:22:39.151Z</updated>
<content type="html"><![CDATA[<h4 id="一、常用命令"><a href="#一、常用命令" class="headerlink" title="一、常用命令"></a>一、常用命令</h4><h5 id="1、容器生命周期管理"><a href="#1、容器生命周期管理" class="headerlink" title="1、容器生命周期管理"></a>1、容器生命周期管理</h5><ol><li>运行容器<figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">docker run [-it] [-d] [--name container_name] [-p container_port:host_port] imageId</span><br><span class="line">参数详解:</span><br><span class="line">-i 打开容器的标准输入STDIN。</span><br><span class="line">-t 为容器建立一个命令行终端。Ctrl+D退出容器</span><br><span class="line">-d 以deamon后台运行</span><br><span class="line">-p 宿主机与容器端口建立映射</span><br><span class="line">--name 为容器命名一个name</span><br></pre></td></tr></table></figure></li></ol><a id="more"></a><ol start="2"><li><p>进入运行中的容器<br><code>docker exec -it container_id /bin/sh</code></p></li><li><p>查看运行中的容器日志信息<br><code>docker logs container_id</code></p></li><li><p>停止所有容器<br><code>docker stop $(docker ps -qa)</code></p></li><li><p>删除所有容器<br><code>docker rm [-f] $(docker ps -qa)</code></p></li><li><p>删除所有镜像<br><code>docker rmi [-f] $(docker ps -qa)</code></p></li><li><p>导入导出(未操作,待添加)<br><code>docker load</code><br><code>docker save</code><br><code>docker export</code><br><code>docker import</code></p></li></ol><h5 id="2、容器操作"><a href="#2、容器操作" class="headerlink" title="2、容器操作"></a>2、容器操作</h5><ol><li><p>新建容器<br><code>docker build -t container_name/container_tag</code> ./</p></li><li><p>容器开启/关闭/重启<br><code>docker start/stop/restart container_id</code></p></li><li><p>查看容器详细信息<br><code>docker inspect container_id</code></p></li><li><p>查看容器端口信息<br><code>docker port container_id</code></p></li><li><p>查看运行中的容器<br><code>docker ps</code></p></li><li><p>重新命名容器名称<br><code>docker rename container_id new_name</code></p></li><li><p>删除容器<br><code>docker rm [-f] container_id</code></p></li><li><p>进入容器(进入到容器启动命令的终端)<br><code>docker attach 94ab7a046f7c</code></p></li></ol><h5 id="3、镜像仓库"><a href="#3、镜像仓库" class="headerlink" title="3、镜像仓库"></a>3、镜像仓库</h5><ol><li><p>查看docker信息<br><code>docker info</code><br>(要点:Registry: <a href="https://index.docker.io/v1/" target="_blank" rel="noopener">https://index.docker.io/v1/</a> 镜像仓库地址)</p></li><li><p>查看本地镜像文件<br><code>docker images</code></p></li><li><p>查看镜像<br><code>docker search whalesay</code> //从镜像仓库中查询镜像文件</p></li><li><p>拉取镜像<br><code>docker pull whalesay</code></p></li><li><p>推送本地镜像到远程仓库(注:必须先登录,之后才能成功推送。登录使用<code>docker login</code>)<br><code>docker push myname/whalesay</code></p></li><li><p>删除镜像<br><code>docker rmi [-f] container_id</code></p></li><li><p>Docker重命名镜像名称和TAG<br><code>docker tag IMAGEID(镜像id) REPOSITORY:TAG(仓库:标签)</code></p></li></ol><h4 id="二、Docker概念"><a href="#二、Docker概念" class="headerlink" title="二、Docker概念"></a>二、Docker概念</h4><p>Docker是开发人员和系统管理员开发、部署和运行带有容器的应用程序的平台。使用Linux容器来部署应用程序称为“容器化”。容器不是一个新概念,但是使用它们能够轻松部署应用程序。</p><p><strong>容器越来越受欢迎,有如下优点:</strong></p><ul><li>灵活:即使是最复杂的应用程序也可以被容器化</li><li>轻量级:容器利用并共享宿主内核</li><li>可互换:您可以动态地部署更新和升级</li><li>可移植:您可以在本地构建,部署到云中,并在任何地方运行</li><li>可伸缩:您可以增加并自动分发容器副本。</li></ul><p>Docker有三个大的概念:<em>Images(镜像)</em>、<em>Containers(容器)</em>、<em>Registry(仓库)</em></p><blockquote><p><strong>Docker 镜像</strong><br>Docker 镜像是Docker容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。UnionFS 允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。正因为有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,比如升级到某个程序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立(在使用虚拟机的时候你可能会这么做),只是一个新 的层被添加或升级了。现在你不用重新发布整个镜像,只需要升级,层使得分发 Docker 镜像变得简单和快速。</p></blockquote><blockquote><p><strong>Docker 仓库</strong><br>Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker 仓库也有公有和私有的概念。公有的 Docker 仓库名字是 Docker Hub。Docker Hub 提供了庞大的镜像集合供使用。这些镜像可以是自己创建,或者在别人的镜像基础上创建。Docker 仓库是 Docker 的分发部分。</p></blockquote><blockquote><p><strong>Docker 容器</strong><br>Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。</p></blockquote><p><strong>镜像和容器:</strong><br>一个容器是通过运行一个图像来启动的。图像是一个可执行的包,它包含运行应用程序所需的一切——代码、运行时、库、环境变量和配置文件。</p><p><strong>容器和虚拟机:</strong><br>一个容器在Linux上运行,并与其他容器共享主机的内核。它运行一个离散的过程,没有比任何其他可执行文件更少的内存,使它变得轻量级。<br>相比之下,虚拟机(VM)运行一个成熟的“客户”操作系统,通过虚拟机监控程序虚拟访问主机资源。一般来说,VMs提供的环境比大多数应用程序需要的资源都多。</p><table><br> <tr><br> <td><center><img src="/uploads/2018/09/container_vm_01.png"></center></td><br> <td><center><img src="/uploads/2018/09/container_vm_02.png"></center></td><br> </tr><br></table><h4 id="三、安装"><a href="#三、安装" class="headerlink" title="三、安装"></a>三、安装</h4><h5 id="1、Windows版"><a href="#1、Windows版" class="headerlink" title="1、Windows版"></a>1、Windows版</h5><p>win7、win8 等需要利用 docker toolbox 来安装,国内可以使用阿里云的镜像来下载,下载地址:<a href="http://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/" target="_blank" rel="noopener">传送门</a><br>win10 直接下载官方的安装包:<a href="http://www.docker-cn.com/community-edition#/overview" target="_blank" rel="noopener">传送门</a></p><blockquote><p>docker toolbox 是一个工具集,它主要包含以下一些内容:<br><figure class="highlight plain"><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">Docker CLI 客户端,用来运行docker引擎创建镜像和容器</span><br><span class="line">Docker Machine. 可以让你在windows的命令行中运行docker引擎命令</span><br><span class="line">Docker Compose. 用来运行docker-compose命令</span><br><span class="line">Kitematic. 这是Docker的GUI版本</span><br><span class="line">Docker QuickStart shell. 这是一个已经配置好Docker的命令行环境</span><br><span class="line">Oracle VM Virtualbox. 虚拟机</span><br></pre></td></tr></table></figure></p></blockquote><p>下载完成之后直接点击安装,安装成功后,桌边会出现三个图标,入下图所示:<br><img src="/uploads/2018/09/docker-toolbox-01.png" alt=""></p><h5 id="2、Linux版"><a href="#2、Linux版" class="headerlink" title="2、Linux版"></a>2、Linux版</h5><ol><li><p>移除旧的版本</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">$ sudo yum remove docker \</span><br><span class="line"> docker-client \</span><br><span class="line"> docker-client-latest \</span><br><span class="line"> docker-common \</span><br><span class="line"> docker-latest \</span><br><span class="line"> docker-latest-logrotate \</span><br><span class="line"> docker-logrotate \</span><br><span class="line"> docker-selinux \</span><br><span class="line"> docker-engine-selinux \</span><br><span class="line"> docker-engine</span><br></pre></td></tr></table></figure></li><li><p>安装一些必要的系统工具<br><code>sudo yum install -y yum-utils device-mapper-persistent-data lvm2</code></p></li><li><p>添加软件源信息<br><code>sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo</code></p><blockquote><p>如果报错:<br>使用yum命令报错File “/bin/yum-config-manager”, line 133 except yum.Errors.RepoError, e: SyntaxError: invalid syntax问题<br><code>vim /bin/yum-config-manager</code>打开,可看见首行为 /usr/bin/python ,由报错可看出使用的是Python2的语法,而我单独安装了Python3,且设置为默认版本导致的语法错误。将/usr/bin/python2 更改为使用版本2的即可。</p></blockquote></li><li><p>更新 yum 缓存<br><code>sudo yum makecache fast</code></p></li><li><p>安装Docker-ce<br><code>sudo yum -y install docker-ce</code></p></li><li><p>启动Docker后台服务<br><code>sudo systemctl start docker</code></p></li><li><p>测试运行 hello-world<br><code>docker run hello-world</code></p></li></ol><p><strong>镜像加速</strong><br>鉴于国内网络问题,后续拉取 Docker 镜像十分缓慢,我们可以需要配置加速器来解决。<br>比较常用的是网易的镜像中心和daocloud镜像市场。 </p><ul><li>网易镜像中心:<a href="https://c.163.com/hub#/m/home/" target="_blank" rel="noopener">https://c.163.com/hub#/m/home/</a> </li><li>daocloud镜像市场:<a href="https://hub.daocloud.io/" target="_blank" rel="noopener">https://hub.daocloud.io/</a></li></ul><p>我使用的是网易的镜像地址:<a href="http://hub-mirror.c.163.com。请在该配置文件中加入(没有该文件的话,请先建一个。配置文件默认是在" target="_blank" rel="noopener">http://hub-mirror.c.163.com。请在该配置文件中加入(没有该文件的话,请先建一个。配置文件默认是在</a> /etc/default/docker):<br><figure class="highlight plain"><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><br><span class="line"> "registry-mirrors": ["http://hub-mirror.c.163.com"]</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>所以刚开始我在寻找/etc/default/docker这个配置文件,一直找不到,后来发现是因为系统和版本的差异。<br>在centos7上这个配置文件已经被更改为 /etc/docker/daemon.json 。<br>可以在这个配置中添加相应的registry-mirrors路径 。<br>原来是这样:<br><figure class="highlight plain"><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">[root@localhost docker]# cat daemon.json </span><br><span class="line">{</span><br><span class="line"> "live-restore": true</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>添加后:<br><figure class="highlight plain"><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><br><span class="line"> "registry-mirrors": ["http://ef017c13.m.daocloud.io"],</span><br><span class="line"> "live-restore": true</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>可以手动vim添加,也可以使用daocloud给出的命令直接更改(建议使用命令)<br><code>[root@localhost docker]# curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://ef017c13.m.daocloud.io</code><br>更改后重启docker<br><code>systemctl restart docker</code></p><p><strong>删除Docker CE</strong><br><figure class="highlight plain"><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">yum remove docker-ce</span><br><span class="line">rm -rf /var/lib/docker</span><br></pre></td></tr></table></figure></p>]]></content>
<summary type="html">
<h4 id="一、常用命令"><a href="#一、常用命令" class="headerlink" title="一、常用命令"></a>一、常用命令</h4><h5 id="1、容器生命周期管理"><a href="#1、容器生命周期管理" class="headerlink" title="1、容器生命周期管理"></a>1、容器生命周期管理</h5><ol>
<li>运行容器<figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">docker run [-it] [-d] [--name container_name] [-p container_port:host_port] imageId</span><br><span class="line">参数详解:</span><br><span class="line">-i 打开容器的标准输入STDIN。</span><br><span class="line">-t 为容器建立一个命令行终端。Ctrl+D退出容器</span><br><span class="line">-d 以deamon后台运行</span><br><span class="line">-p 宿主机与容器端口建立映射</span><br><span class="line">--name 为容器命名一个name</span><br></pre></td></tr></table></figure>
</li>
</ol>
</summary>
<category term="Docker" scheme="http://yoursite.com/categories/Docker/"/>
<category term="Docker" scheme="http://yoursite.com/tags/Docker/"/>
</entry>
</feed>