-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
2572 lines (2190 loc) · 199 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<!--[if lt IE 7]>
<html class="ie ie6 lte9 lte8 lte7" lang="zh-CN">
<![endif]--><!--[if IE 7]>
<html class="ie ie7 lte9 lte8 lte7" lang="zh-CN">
<![endif]--><!--[if IE 8]>
<html class="ie ie8 lte9 lte8" lang="zh-CN">
<![endif]--><!--[if IE 9]>
<html class="ie ie9" lang="zh-CN">
<![endif]--><!--[if gt IE 9]>
<html lang="zh-CN"> <![endif]--><!--[if !IE]><!--><html lang="zh-CN">
<!--<![endif]-->
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0,maximum-scale=3.0,width=device-width">
<link rel="profile" href="http://gmpg.org/xfn/11">
<link rel="pingback" href="./xmlrpc.php">
<!-- IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://yankay.com/wp-content/themes/neuro/inc/js/html5.js" type="text/javascript"></script>
<![endif]-->
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1">
<!-- This site is optimized with the Yoast SEO plugin v16.4 - https://yoast.com/wordpress/plugins/seo/ -->
<title>我自然 - 颜开的博客</title>
<link rel="canonical" href="./index.html">
<link rel="next" href="./page/2/index.html">
<meta property="og:locale" content="zh_CN">
<meta property="og:type" content="website">
<meta property="og:title" content="我自然 - 颜开的博客">
<meta property="og:url" content="./index.html">
<meta property="og:site_name" content="我自然">
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json" class="yoast-schema-graph">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":".//#website","url":".//","name":"我自然","description":"颜开的博客","potentialAction":[{"@type":"SearchAction","target":".//?s={search_term_string}","query-input":"required name=search_term_string"}],"inLanguage":"zh-CN"},{"@type":"CollectionPage","@id":".//#webpage","url":".//","name":"我自然 - 颜开的博客","isPartOf":{"@id":".//#website"},"breadcrumb":{"@id":".//#breadcrumb"},"inLanguage":"zh-CN","potentialAction":[{"@type":"ReadAction","target":[".//"]}]},{"@type":"BreadcrumbList","@id":".//#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"item":{"@id":".//#webpage"}}]}]}</script>
<!-- / Yoast SEO plugin. -->
<link rel="alternate" type="application/rss+xml" title="我自然 » Feed" href="./feed/index.html">
<link rel="alternate" type="application/rss+xml" title="我自然 » 评论Feed" href="./comments/feed/index.html">
<link rel="shortcut icon" href="http://47.100.65.109/wp-content/uploads/2021/03/favicon.png" type="image/x-icon">
<script type="text/javascript">
/* <![CDATA[ */
window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/72x72\/","ext":".png","svgUrl":"https:\/\/s.w.org\/images\/core\/emoji\/14.0.0\/svg\/","svgExt":".svg","source":{"concatemoji":".\/\/wp-includes\/js\/wp-emoji-release.min.js?ver=6.4.2"}};
/*! This file is auto-generated */
!function(i,n){var o,s,e;function c(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(o,JSON.stringify(t))}catch(e){}}function p(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data),r=(e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0),new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data));return t.every(function(e,t){return e===r[t]})}function u(e,t,n){switch(t){case"flag":return n(e,"🏳️⚧️","🏳️⚧️")?!1:!n(e,"🇺🇳","🇺🇳")&&!n(e,"🏴","🏴");case"emoji":return!n(e,"🫱🏻🫲🏿","🫱🏻🫲🏿")}return!1}function f(e,t,n){var r="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):i.createElement("canvas"),a=r.getContext("2d",{willReadFrequently:!0}),o=(a.textBaseline="top",a.font="600 32px Arial",{});return e.forEach(function(e){o[e]=t(a,e,n)}),o}function t(e){var t=i.createElement("script");t.src=e,t.defer=!0,i.head.appendChild(t)}"undefined"!=typeof Promise&&(o="wpEmojiSettingsSupports",s=["flag","emoji"],n.supports={everything:!0,everythingExceptFlag:!0},e=new Promise(function(e){i.addEventListener("DOMContentLoaded",e,{once:!0})}),new Promise(function(t){var n=function(){try{var e=JSON.parse(sessionStorage.getItem(o));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(s),u.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"}),a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=function(e){c(n=e.data),a.terminate(),t(n)})}catch(e){}c(n=f(s,u,p))}t(n)}).then(function(e){for(var t in e)n.supports[t]=e[t],n.supports.everything=n.supports.everything&&n.supports[t],"flag"!==t&&(n.supports.everythingExceptFlag=n.supports.everythingExceptFlag&&n.supports[t]);n.supports.everythingExceptFlag=n.supports.everythingExceptFlag&&!n.supports.flag,n.DOMReady=!1,n.readyCallback=function(){n.DOMReady=!0}}).then(function(){return e}).then(function(){var e;n.supports.everything||(n.readyCallback(),(e=n.source||{}).concatemoji?t(e.concatemoji):e.wpemoji&&e.twemoji&&(t(e.twemoji),t(e.wpemoji)))}))}((window,document),window._wpemojiSettings);
/* ]]> */
</script>
<style id="wp-emoji-styles-inline-css" type="text/css">img.wp-smiley, img.emoji {
display: inline !important;
border: none !important;
box-shadow: none !important;
height: 1em !important;
width: 1em !important;
margin: 0 0.07em !important;
vertical-align: -0.1em !important;
background: none !important;
padding: 0 !important;
}</style>
<link rel="stylesheet" id="wp-block-library-css" href="./wp-includes/css/dist/block-library/style.min.css?ver=6.4.2" type="text/css" media="all">
<style id="classic-theme-styles-inline-css" type="text/css">/*! This file is auto-generated */
.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}</style>
<style id="global-styles-inline-css" type="text/css">body{--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--gray: #777;--wp--preset--color--light-gray: #f5f5f5;--wp--preset--color--blue: #0286cf;--wp--preset--color--legacy: #b6b6b6;--wp--preset--color--red: #c80a00;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
.wp-block-navigation a:where(:not(.wp-element-button)){color: inherit;}
:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}
:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}
.wp-block-pullquote{font-size: 1.5em;line-height: 1.6;}</style>
<link rel="stylesheet" id="bootstrap-style-css" href="./wp-content/themes/neuro/cyberchimps/lib/bootstrap/css/bootstrap.min.css?ver=2.0.4" type="text/css" media="all">
<link rel="stylesheet" id="bootstrap-responsive-style-css" href="./wp-content/themes/neuro/cyberchimps/lib/bootstrap/css/bootstrap-responsive.min.css?ver=2.0.4" type="text/css" media="all">
<link rel="stylesheet" id="font-awesome-css" href="./wp-content/themes/neuro/cyberchimps/lib/css/font-awesome.min.css?ver=6.4.2" type="text/css" media="all">
<link rel="stylesheet" id="cyberchimps_responsive-css" href="./wp-content/themes/neuro/cyberchimps/lib/bootstrap/css/cyberchimps-responsive.min.css?ver=1.0" type="text/css" media="all">
<link rel="stylesheet" id="core-style-css" href="./wp-content/themes/neuro/cyberchimps/lib/css/core.css?ver=1.0" type="text/css" media="all">
<link rel="stylesheet" id="style-css" href="./wp-content/themes/neuro/style.css?ver=1.0" type="text/css" media="all">
<link rel="stylesheet" id="elements_style-css" href="./wp-content/themes/neuro/elements/lib/css/elements.css?ver=6.4.2" type="text/css" media="all">
<script>
/* <![CDATA[ */
var rcewpp = {
"ajax_url":"http://yankay.com/wp-admin/admin-ajax.php",
"nonce": "aa462ebe7f",
"home_url": "http://yankay.com/",
"settings_icon": 'http://yankay.com/wp-content/plugins/export-wp-page-to-static-html/admin/images/settings.png',
"settings_hover_icon": 'http://yankay.com/wp-content/plugins/export-wp-page-to-static-html/admin/images/settings_hover.png'
};
/* ]]\> */
</script>
<script type="text/javascript" src="./wp-includes/js/jquery/jquery.min.js?ver=3.7.1" id="jquery-core-js"></script>
<script type="text/javascript" src="./wp-includes/js/jquery/jquery-migrate.min.js?ver=3.4.1" id="jquery-migrate-js"></script>
<script type="text/javascript" src="./wp-content/themes/neuro/cyberchimps/lib/js/jquery.slimbox.min.js?ver=1.0" id="slimbox-js"></script>
<script type="text/javascript" src="./wp-content/themes/neuro/cyberchimps/lib/js/jquery.jcarousel.min.js?ver=1.0" id="jcarousel-js"></script>
<script type="text/javascript" src="./wp-content/themes/neuro/cyberchimps/lib/js/jquery.mobile.custom.min.js?ver=6.4.2" id="jquery-mobile-touch-js"></script>
<script type="text/javascript" src="./wp-content/themes/neuro/cyberchimps/lib/js/swipe-call.min.js?ver=6.4.2" id="slider-call-js"></script>
<script type="text/javascript" src="./wp-content/themes/neuro/cyberchimps/lib/js/core.min.js?ver=6.4.2" id="core-js-js"></script>
<script type="text/javascript" src="./wp-content/themes/neuro/elements/lib/js/elements.min.js?ver=6.4.2" id="elements_js-js"></script>
<link rel="https://api.w.org/" href="./wp-json/index.html">
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="./xmlrpc.php?rsd">
<meta name="generator" content="WordPress 6.4.2">
<style type="text/css">.ie8 .container {max-width: 1020px;width:auto;}</style>
<style type="text/css">.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>
<style type="text/css" media="all">body {
font-size : 16px;
font-family : "Open Sans", Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight : normal;
color : #333333;
}
.container {
max-width : 1020px;
}
h1, h2, h3, h4, h5, h6 {
font-family : Arial, Helvetica, sans-serif;
}</style>
<link rel="icon" href="./wp-content/uploads/2021/03/cropped-favicon-32x32.png" sizes="32x32">
<link rel="icon" href="./wp-content/uploads/2021/03/cropped-favicon-192x192.png" sizes="192x192">
<link rel="apple-touch-icon" href="./wp-content/uploads/2021/03/cropped-favicon-180x180.png">
<meta name="msapplication-TileImage" content="./wp-content/uploads/2021/03/cropped-favicon-270x270.png">
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-10148377-3"></script>
<script>window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-10148377-3');</script>
</head>
<body class="home blog cc-responsive">
<!-- ---------------- Menu --------------------- -->
<div class="container-full-width" id="navigation_menu">
<div class="container">
<div class="container-fluid">
<nav id="navigation" role="navigation">
<div class="main-navigation navbar">
<div class="navbar-inner">
<div class="container">
<div class="nav-collapse collapse">
<div class="menu-%e4%b8%bb%e8%8f%9c%e5%8d%95-container"><ul id="menu-%e4%b8%bb%e8%8f%9c%e5%8d%95" class="nav">
<li id="menu-item-27229" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item menu-item-home menu-item-27229"><a href="./index.html">首页</a></li>
<li id="menu-item-26815" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-26815"><a href="./about/index.html">关于</a></li>
</ul></div>
</div>
<!-- collapse -->
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
</div>
<!-- container -->
</div>
<!-- .navbar-inner .row-fluid -->
</div>
<!-- main-navigation navbar -->
</nav>
<!-- #navigation -->
</div>
<!-- .container-fluid-->
</div>
<!-- .container -->
</div>
<!-- #navigation_menu -->
<!-- --------------- Sub Body -------------------- -->
<div class="container-full-width" id="sub_body">
<!-- ---------------- Header --------------------- -->
<div class="container-full-width" id="header_section">
<div class="container">
<div class="container-fluid">
<header id="cc-header" class="row-fluid">
<div class="span7">
<div class="hgroup">
<h2 class="site-title"><a href="./index.html" title="我自然" rel="home">我自然</a></h2>
</div>
</div>
<div id="register" class="span5">
<div id="social">
<div class="legacy-icons">
</div>
</div>
</div>
</header>
</div>
<!-- .container-fluid-->
</div>
<!-- .container -->
</div>
<!-- #header_section -->
<div class="container-full-width" id="blog_post_page_section">
<div class="container">
<div class="container-fluid">
<div id="container" class="row-fluid">
<div id="content" class=" span9 content-sidebar-right">
<article id="post-27289" class="post-27289 post type-post status-publish format-standard hentry category-5 tag-containerd">
<header class="entry-header">
<h2 class="entry-title">
<a href="./containerd-will-replace-docker/index.html" title="连结到听说 Docker 被 kubenetes 抛弃了,怎么办?containerd" rel="bookmark">听说 Docker 被 kubenetes 抛弃了,怎么办?containerd</a>
</h2>
<div class="entry-meta">
在 <a href="./containerd-will-replace-docker/index.html" title="下午7:29" rel="bookmark">
<time class="entry-date updated" datetime="2021-06-12T19:29:52+08:00">2021年6月12日</time>
</a> 上公布 <span class="byline"> 作者为 <span class="author vcard">
<a class="url fn n" href="./author/yankay/index.html" title="查看 yankay 的所有文章" rel="author">yankay</a>
</span>
</span> </div>
<!-- .entry-meta -->
</header>
<!-- .entry-header -->
<div class="entry-content">
<p>原文地址:<a rel="noreferrer noopener" href="http://blog.daocloud.io/containerd-1-5-%e9%9c%87%e6%92%bc%e5%8f%91%e5%b8%83-%e6%94%af%e6%8c%81%e9%95%9c%e5%83%8f%e5%8a%a0%e5%af%86%e7%9a%84%e5%ae%b9%e5%99%a8%e5%bc%95%e6%93%8e/" target="_blank">原文链接</a>,作者: <a href="https://github.com/wzshiming">张世明</a></p>
<p>Containerd 是 Kubernetes 默认的标准 CRI 运行时环境,被 Kubernetes, Docker 等各种项目使用。也是 CNCF 唯一的容器运行时。Docker 在最近这些年 ,没有太多新特性引入,而更轻量的 containerd 正在蓬勃发展。 <a href="https://www.infoq.cn/article/x14tvb7izidjpjheoeuj">Docker公司 正在衰落</a>,<strong>Containerd 将继承衣钵,成为未来容器引擎的实施标准。</strong></p>
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="621" src="./wp-content/uploads/2021/06/containerd-architecture-1024x621.png" alt="" class="wp-image-27292" srcset="./wp-content/uploads/2021/06/containerd-architecture-1024x621.png 1024w, ./wp-content/uploads/2021/06/containerd-architecture-300x182.png 300w, ./wp-content/uploads/2021/06/containerd-architecture-768x465.png 768w, ./wp-content/uploads/2021/06/containerd-architecture-1536x931.png 1536w, ./wp-content/uploads/2021/06/containerd-architecture.png 1782w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>
<h2 class="wp-block-heading">Containerd 的使用情况</h2>
<p>Containerd 并非一个 全新技术,它是由 Docker 公司开源,作为 docker 的核心组件存在。根据社区中的几个托管服务和开源项目使用的统计,到 2020 年止 Containerd 的使用 (包含在 Docker 中使用) 占容器使用的 83%。</p>
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="413" src="./wp-content/uploads/2021/06/企业微信截图_16234983158073-1024x413.png" alt="" class="wp-image-27302" srcset="./wp-content/uploads/2021/06/企业微信截图_16234983158073-1024x413.png 1024w, ./wp-content/uploads/2021/06/企业微信截图_16234983158073-300x121.png 300w, ./wp-content/uploads/2021/06/企业微信截图_16234983158073-768x310.png 768w, ./wp-content/uploads/2021/06/企业微信截图_16234983158073-1536x619.png 1536w, ./wp-content/uploads/2021/06/企业微信截图_16234983158073.png 1954w" sizes="(max-width: 1024px) 100vw, 1024px"><figcaption>continerd 可以作为 kubelet 和 docker 的 容器引擎使用,也可以单独使用</figcaption></figure>
<p> 根据 Sysdig 的统计数据,从 2019 年 到 2020 年,conatinerd 的独立使用率,上升了 2倍。上升趋势明显。</p>
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="370" src="./wp-content/uploads/2021/06/企业微信截图_16234985914716-1024x370.png" alt="" class="wp-image-27303" srcset="./wp-content/uploads/2021/06/企业微信截图_16234985914716-1024x370.png 1024w, ./wp-content/uploads/2021/06/企业微信截图_16234985914716-300x108.png 300w, ./wp-content/uploads/2021/06/企业微信截图_16234985914716-768x278.png 768w, ./wp-content/uploads/2021/06/企业微信截图_16234985914716-1536x555.png 1536w, ./wp-content/uploads/2021/06/企业微信截图_16234985914716.png 1914w" sizes="(max-width: 1024px) 100vw, 1024px"></figure>
<h2 class="wp-block-heading">Containerd 1.5 的一些新特性</h2>
<p>最近的<a rel="noreferrer noopener" href="https://github.com/containerd/containerd/releases" target="_blank">Containerd 1.5</a> 以于2021年5月4日发布。这是 Containerd的第6个主要版本包括许多稳定性改进, 以及代码组织结构的变化使后续开发更方便。该版本默认启用支持 OCI crypt 解密,并引入了对zstd、NRI 和 FreeBSD 的实验性支持,还包括CRI插件纳入主容器库和切换到Go modules。</p>
<h3 class="wp-block-heading" id="id-震惊-Containerd1.5发布-支持镜像加密的容器引擎-更好的压缩算法支持">更好的压缩算法支持</h3>
<p>现在除了 gzip 之外,还支持 zstd 作为镜像压缩算法。zstd 是 Facebook 在2016年开源的新无损压缩算法,优点是压缩率和压缩/解压缩性能都很突出。</p>
<p>zstd 的设计目的是达到与 deflate 算法(开发于1991年,用于gzip) 相当的压缩比, 并且更快,尤其是解压的时候。</p>
<p>zstd 在其最大压缩级别的压缩比接近 lzma、lzham 和 ppmx,并且比 lza 和 bzip2 性能更好。它的解压速度比任何当前可用的算法都快,并且压缩比更好。</p>
<p><code><a rel="noreferrer noopener" href="https://github.com/klauspost/compress/tree/master/zstd" target="_blank">zstd</a> 的</code><a rel="noreferrer noopener" href="https://github.com/klauspost/compress/blob/master/zstd/README.md" target="_blank">基准测试结果</a> 在速度方面,在最快模式下,它的速度通常是 stdlib deflate/gzip 2倍。</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="736" height="241" src="./wp-content/uploads/2021/06/GJQ_1wCBa0G6DvoDACqDn0MAAAAAbj0JAAAB.jpg" alt="" class="wp-image-27295" srcset="./wp-content/uploads/2021/06/GJQ_1wCBa0G6DvoDACqDn0MAAAAAbj0JAAAB.jpg 736w, ./wp-content/uploads/2021/06/GJQ_1wCBa0G6DvoDACqDn0MAAAAAbj0JAAAB-300x98.jpg 300w" sizes="(max-width: 736px) 100vw, 736px"></figure>
<h3 class="wp-block-heading">支持加密镜像</h3>
<p>可以把镜像加密后上传到镜像仓库, Containerd 只需要配置解码的 key 就可以运行这加密的镜像, 对于一些对于安全性有需求的镜像可以使用这种方式。</p>
<p>自从 Containerd 1.3 加入该功能后,已支持容器使用 <a href="https://github.com/containers/ocicrypt">加密镜像 (OCI crypt)</a> 但是一直并没有启用该功能。</p>
<p>该特性将在 1.5 中已经默认启用,使用方法请参见<a href="https://github.com/containerd/containerd/blob/v1.5.0/docs/cri/decryption.md">文档</a> (依赖的二进制文件包含在 <a href="https://github.com/containerd/containerd/releases">cri-containerd-cni-1.5.0-linux-amd64.tar.gz</a> )</p>
<p>注意:当前 Docker 是不支持 OCI crypt 的,因为 Docker 目前还没有使用 Containerd 管理镜像。</p>
<h3 class="wp-block-heading">节点资源接口</h3>
<p>节点资源接口(<a href="https://github.com/containerd/nri">NRI</a>) 用于 CPU 调度约束和内存配额的标准接口。</p>
<p>其类似容器网络接口(<a href="https://www.cni.dev/">CNI</a>)的基本接口、概念和插件设计是一种处理容器网络堆栈的多种实现的优雅方式。此概念可用于其他接口,以定制容器的运行时环境。节点资源接口(<a href="https://github.com/containerd/nri">NRI</a>)是一个新的接口,其实带有结构化API和容器插件设计,用对节点上的资源进行管理。与 CNI 相同 NRI 插件将在容器创建完毕, 但是还没有真正启动之前的初始化时被调用。</p>
<p>可以看<a href="https://github.com/containerd/nri#sample-plugin">示例代码</a>了解 NRI 的使用。</p>
<h3 class="wp-block-heading">支持 FreeBSD</h3>
<p>现在支持在 FreeBSD 运行 Containerd,容器运行时 OCI 是使用 <a href="https://en.wikipedia.org/wiki/FreeBSD_jail">FreeBSD jails</a> (Samuel Karp 的 <code><a href="https://github.com/samuelkarp/runj">runj</a></code>)。文件系统目前仅支持 ZFS, 后续计划支持 <code><a href="https://www.freebsd.org/cgi/man.cgi?query=unionfs&sektion=8&manpath=freebsd-release-ports">unionfs</a></code>。</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="977" height="416" src="./wp-content/uploads/2021/06/1_Wu1CiRsPaGoiqNaeLJrWVg.png" alt="" class="wp-image-27296" srcset="./wp-content/uploads/2021/06/1_Wu1CiRsPaGoiqNaeLJrWVg.png 977w, ./wp-content/uploads/2021/06/1_Wu1CiRsPaGoiqNaeLJrWVg-300x128.png 300w, ./wp-content/uploads/2021/06/1_Wu1CiRsPaGoiqNaeLJrWVg-768x327.png 768w" sizes="(max-width: 977px) 100vw, 977px"></figure>
<h2 class="wp-block-heading">结尾</h2>
<p>原文作者“张世明”是 任职 DaoCloud 研发团队的 天才青年,在过去的 半年,在 containerd 社区 <strong>排名第八</strong>的贡献者。</p>
<p>感谢“<a href="https://www.yuque.com/alipayko5m44vl0y">胖橘</a>“对本文的润色加工。</p>
<p><strong>各位观众老爷,您是否看好 containerd 呢?</strong></p>
</div>
<!-- .entry-content -->
<footer class="entry-meta">
<span class="cat-links">
文章分类 <a href="./category/%e6%8a%80%e6%9c%af/index.html" rel="category tag">软件技术</a> </span>
<span class="sep"> | </span>
<span class="taglinks">
标签: <a href="./tag/containerd/index.html" rel="tag">containerd</a> </span>
<span class="sep"> | </span>
<span class="comments-link"><a href="./containerd-will-replace-docker/index.html#respond">发表评论</a></span>
<span class="sep"> | </span>
</footer>
<!-- #entry-meta -->
</article><!-- #post-27289 -->
<article id="post-27267" class="post-27267 post type-post status-publish format-standard hentry category-3">
<header class="entry-header">
<h2 class="entry-title">
<a href="./%e5%85%ac%e5%91%8a-%e5%8d%9a%e5%ae%a2%e9%87%8d%e5%bc%80%e4%ba%86/index.html" title="连结到公告 – 博客重开了" rel="bookmark">公告 – 博客重开了</a>
</h2>
<div class="entry-meta">
在 <a href="./%e5%85%ac%e5%91%8a-%e5%8d%9a%e5%ae%a2%e9%87%8d%e5%bc%80%e4%ba%86/index.html" title="下午10:15" rel="bookmark">
<time class="entry-date updated" datetime="2021-03-28T22:15:29+08:00">2021年3月28日</time>
</a> 上公布 <span class="byline"> 作者为 <span class="author vcard">
<a class="url fn n" href="./author/yankay/index.html" title="查看 yankay 的所有文章" rel="author">yankay</a>
</span>
</span> </div>
<!-- .entry-meta -->
</header>
<!-- .entry-header -->
<div class="entry-content">
<p>尊敬的读者,博客重开了。</p>
<p>“我自然“这个博客,从2008年开始写,到现在已经13年了。期间记录了不少点点滴滴。中间不但断更,而且博客图床数据也被删除了。不过好在终于成功恢复。未来会有更多的精彩内容。</p>
<p>最近这 6年间,笔者是去创业(<a href="http://www.daocloud.io/" data-type="URL" data-id="www.daocloud.io">DaoCloud</a>)去了,之所以断更 主要是因为 “特别忙“ – 真的特别忙,博客坏了3年,却没有3个小时去修理,更别提更新什么文章了。 不过对于工作来说,这样的忙法是病态的,而且也不知道还要忙到什么时候。既然如此,那还是把博客捡起来吧。</p>
<p>接下来这个博客,我还是会多谢写一些技术干货,穿插一点点生活故事。有人会问 “我自然” 这个博客标题是什么意思。“我自然“,是一种自然而然, 怡然快乐的感觉。在现代社会每个人都被资本或政治异化,变成了“人力资源”,“资本家” 这些非自然的形象。 通过读一读这个博客,也希望能够给读者回到更自然快乐的感觉。</p>
<div class="wp-block-image"><figure class="alignleft size-large"><img loading="lazy" decoding="async" width="640" height="426" src="http://47.100.65.109/wp-content/uploads/2021/03/hailan.jpeg" alt="" class="wp-image-27271" srcset="./wp-content/uploads/2021/03/hailan.jpeg 640w, ./wp-content/uploads/2021/03/hailan-300x200.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px"></figure></div>
</div>
<!-- .entry-content -->
<footer class="entry-meta">
<span class="cat-links">
文章分类 <a href="./category/%e5%ae%b6%e5%ba%ad%e7%94%9f%e6%b4%bb/index.html" rel="category tag">家庭生活</a> </span>
<span class="sep"> | </span>
<span class="comments-link"><a href="./%e5%85%ac%e5%91%8a-%e5%8d%9a%e5%ae%a2%e9%87%8d%e5%bc%80%e4%ba%86/index.html#comments">1 条评论</a></span>
<span class="sep"> | </span>
</footer>
<!-- #entry-meta -->
</article><!-- #post-27267 -->
<article id="post-27189" class="post-27189 post type-post status-publish format-standard hentry category-5 tag-cloudfoundry tag-micro-cloudfoundry">
<header class="entry-header">
<h2 class="entry-title">
<a href="./cloudfoundry-v2-with-microcf/index.html" title="连结到CloudFoundry v2面面谈,内赠MicroCFv2福利" rel="bookmark">CloudFoundry v2面面谈,内赠MicroCFv2福利</a>
</h2>
<div class="entry-meta">
在 <a href="./cloudfoundry-v2-with-microcf/index.html" title="下午7:39" rel="bookmark">
<time class="entry-date updated" datetime="2014-02-06T19:39:32+08:00">2014年2月6日</time>
</a> 上公布 <span class="byline"> 作者为 <span class="author vcard">
<a class="url fn n" href="./author/yankay/index.html" title="查看 yankay 的所有文章" rel="author">yankay</a>
</span>
</span> </div>
<!-- .entry-meta -->
</header>
<!-- .entry-header -->
<div class="entry-content">
<p></p>
<p>CloudFoundry 是业界领先的PaaS云平台,可以为应用提供运行平台,类似于运行着无数应用的炙手可热的HeroKu。最近发布的第二代,功能上有了极大的扩充,如BuildPack, Service Broker v2, loggregator,并且用GoLang重写了大部分组件提升性能,如GoRouter,CLI,HM9000。本文带您走进这个大观园。还提供一个MicroCFv2下载,满足您试一试的愿望,只此一家哦。</p>
<p><img loading="lazy" decoding="async" class="alignnone size-medium wp-image-27234" src="http://47.100.65.109/wp-content/uploads/2014/02/run-your-java-code-on-cloud-foundry-andy-piper-pivotal-16-638-300x225.jpeg" alt="" width="300" height="225" srcset="./wp-content/uploads/2014/02/run-your-java-code-on-cloud-foundry-andy-piper-pivotal-16-638-300x225.jpeg 300w, ./wp-content/uploads/2014/02/run-your-java-code-on-cloud-foundry-andy-piper-pivotal-16-638.jpeg 638w" sizes="(max-width: 300px) 100vw, 300px"></p>
<p>CloudFoundry v1已经出现较长时间,在三年前EMC中国研究院就参与其研究。对CloudFoundry v1的研究可以参见彭麟《<a href="http://qing.blog.sina.com.cn/tj/88ca09aa330004r8.html">深入 Cloud Foundry</a>》。在CloudFoundry v2诞生前的三年里,一些事情发生了巨变。外部环境方面,AWS走向成熟,Heroku逐渐成功,摸索到了PaaS成功的道路。OpenStack风起云涌,Docker带着小伙伴们异军突起。面对这些,CloudFoundry面临的竞争加剧,但同时也有了可以配合的伙伴。而CloudFoundry内部也发生了变化,原先隶属于专攻虚拟化的VmWare,现在与时俱进,成为了专攻大数据的Pivotal的一部分。而CloudFoundry v2是CloudFoundry归于Pivotal的第一个版本,成为这家兴新大数据公司的战略一部分。</p>
<p>如果想试试CloudFoundry公有云,可以在<a href="http://www.cloudfoundry.com/use">官网</a>上申请账户。下文主要针对自建CloudFoundry。</p>
<h2>新架构</h2>
<p>是骡子是马,看看架构就懂了。在看第二代的架构之前,我们回顾一下之前的架构。</p>
<p>用户通过VMC Client将应用上传到Cloud Controller 上,Cloud Controller将应用部署到DEA Pool上面。用户可以通过Router访问到各自的应用,Health Manager查看各个APP状态,保证可以自动重启。同时Cloud Controller还提供了各种Services,如MySQL,Redis等等。</p>
<p>在上一代架构中,CloudFoundry呈现出大包大揽的方式,APP的部署也好,Service的提供也好,都自己做。虽然扩展Runtime和Service并不麻烦,但是这需要“CloudFoundry”管理员的介入,租户是没有办法做这些的。另外私有云的玩家往往都有着定制Runtime和Service的需求,内置的Service很难满足需要。当然还有一些问题,如Router性能不佳,协议匮乏。Health Manager单点。</p>
<p>在新的架构中,CloudFoundry有着更加开放的玩法。</p>
<p>第二代CloudFoundry几乎将V1时代组件全部重写,满足新的需要。</p>
<p>APP方面,在上传应用的时候,用户可以同时上传一个BuildPack,这样租户可以根据自己的需要来部署应用,无需通知云管理员。BuildPack是Heroku的部署机制,在社区有着丰富的资源。因此CloudFoundry和Heroku是兼容的。可以部署在Heroku上的应用,也可以部署在CloudFoundry上。还有很多其他PaaS也使用BuildPack,BuildPack已经成为PaaS应用部署的事实标准。</p>
<p>Serivce方面,不再内建Service,而是使用一个更加简洁的Service Broker和User Provided Service设计。用户可以将Service Broker使用现有的XaaS上面,如果OpenStack Trove, AWS RDS。Heroku 有很多<a href="https://addons.heroku.com/">小伙伴们</a> 可以提供各种各样的Service,比如监控服务Relic,国内也有很多,如监控宝。GAE式的PaaS证明关门玩Service是不行的,CloudFoundry走向了开放的道路。另外User Provided Service可以让接上用户现有服务,如Oracle,保护现有资产。</p>
<p>大数据深入人心,CloudFoundry现在的loggregator可以让应用的日子流进Service中。实时数据分析成为可能。</p>
<p>新的的CloudFoundry对运行在IaaS有着天生的亲和力。BOSH可以非常方便的部署CF。Router的性能瓶颈得到解决。UAA可以提供第三方认证。Health Manager也不再是单点。</p>
<h2>开放的App Runtime</h2>
<p>开放的App Runtime的力量来自如Build Pack。我们可以浏览先App 部署的全过程。</p>
<p> </p>
<ol>
<li>用户使用使用CF PUSH命令上传应用</li>
<li>CLI告知CCNG创建一个应用</li>
<li>CCNG在数据库中加入该应用的记录例如应用名称,BuildPack选择</li>
<li>CLI上传程序</li>
<li>CCNG将程序存起来</li>
<li>CLI启动应用</li>
<li>由于应用尚未部署,所以CCNG找一台DEA,在该DEA内执行BuildPack来部署应用</li>
<li>DEA输出运行BuildPack的信息</li>
<li>BuildPack执行完毕,输出是一个DropLet文件(编译打包的结果),DEA将该文件存起来</li>
<li>DEA将打包情况汇报给CCNG</li>
<li>CCNG选择一个DEA来部署应用</li>
<li>应用在DEA中运行,运行结果输出到CCNG</li>
</ol>
<p>可以看到,BuildPack和APP一样都是在一样的环境(DEA)中执行的。BuildPack非常简洁,只需要三个脚本。</p>
<ul>
<li>bin/detect 用来判断该BuildPack是否支持该程序</li>
<li>bin/compile 用来编译,类似Maven的mvn compile</li>
<li>bin/release 用来打包,类型Maven的mvn package</li>
</ul>
<p>现在CloudFoundry内建了三个主要BuildPack,Java BuildPack是自制,Ruby和NodeJs都是沿用Heroku的</p>
<ul>
<li>
<a href="https://github.com/cloudfoundry/java-buildpack">Java BuildPack</a> 支持非常多框架和JVM语言。甚至包括new_relic,这给我们监控CloudFoundry上APP提供思路。</li>
<li><a href="https://github.com/cloudfoundry/heroku-buildpack-ruby">Ruby BuildPack</a></li>
<li><a href="https://github.com/cloudfoundry/heroku-buildpack-nodejs">NodeJs BuildPack</a></li>
</ul>
<p>得益于Heroku的流行,第三方的BuildPack就数不胜数了。可以在<a href="https://devcenter.heroku.com/articles/third-party-buildpacks">Heroku buildpacks</a> 和<a href="https://github.com/cloudfoundry-community/cf-docs-contrib/wiki/Buildpacks"> CloudFoundry Commmunity </a>中找到很多。</p>
<p>Build Pack有一个问题就是每次编译都需要从外网下载依赖,巨大JRE文件和不稳定的网络会使部署失败。不过最近的发布中提供了Build Pack Cache功能,可以有效解决这个问题。在内网中搭建一个Cached Proxy也是不错的办法。</p>
<h2>开放的Service</h2>
<p>CF-Relase是CloudFoundry的发布包,我们可以对比下V1和最近的发布包。</p>
<table>
<tbody>
<tr>
<th> </th>
<th><a href="https://github.com/cloudfoundry/cf-release/tree/v1/jobs">v1</a></th>
<th><a href="https://github.com/cloudfoundry/cf-release/tree/v155/jobs">v2(依据v155)</a></th>
</tr>
<tr>
<td>CloudFoundry Core组件数量</td>
<td>29</td>
<td>21</td>
</tr>
<tr>
<td>Service数量</td>
<td>24</td>
<td> 0</td>
</tr>
</tbody>
</table>
<p>可见在v1版本中有大量的组件是在做Service,摊子铺的很大。而V2中将这个包袱放下,提交给各种第三方XaaS了。连接XaaS和CloudFoundry的中间组件被称为CloudFoudry Broker。v2的Service Broker和v1的完全不同。V2中的设计如下。</p>
<p> </p>
<p>一个Service Broker 需要实现5个API接口,包含三方面</p>
<ul>
<li>Service发现。租户可以向ClouldFoundry提交Add Service 命令,参数是URL。然后ClouldFoundry去调用该URL,发现该URL包含哪些Service</li>
<li>Service创建/删除。自动化的创建Service。</li>
<li>Service绑定/解绑定。将Service的一些访问参数设定成APP的环境变量。</li>
</ul>
<p>Service Broker的部署可以很灵活。既可以作为CloudFoundry的组件,也可以作为CloudFoundry的APP运行在CloudFoundry上。官方提供了一些Service Broker 实现实例。</p>
<ul>
<li><a href="https://github.com/cloudfoundry-samples/github-service-broker-ruby">GitHub repo service</a></li>
<li><a href="https://github.com/cloudfoundry/cf-mysql-release">MySQL database service</a></li>
<li><a href="https://github.com/cloudfoundry-community/spring-service-broker">Spring Service Broker</a></li>
<li><a href="https://github.com/cloudfoundry-community/cf-mysql-java-broker">MySQL Java Broker</a></li>
</ul>
<p>在企业生产环境中,Service的自动化创建并非易事。举MySQL例子,选择版本,机器,网络,存储,备份策略,高可用方案,搞上防火墙,打上自定义补丁等等,一千个生产环境有一千种个MySQL玩法。在现在的玩法中,需要人介入的环节太多,太有必要。不存在一招鲜吃遍天的自动化创建方法。User Provided Service 就是来调和这个矛盾。让Cloud Foundry不强依赖自动化的创建Service。</p>
<p>User Provided Service 很简单,就是用户在创建Service的时候,输入Service访问参数。如用户名,密码,CloudFoundry把这参数存起来,在绑定的时候注入到环境变量中。下面会演示。</p>
<h2>亲昵的大数据</h2>
<p>国内的CloudFoundry玩家大多有开放平台的计划。作为开发平台的运营者,不只要提供一个稳定,开放的平台,获得应用的数据,就等于把握住了脉搏。Pivotal做为一家大数据公司,接手CloudFoundry的一个大改进就是增加了Loggragtor模块。</p>
<p><span style="line-height: 1.5em;"> </span></p>
<p>Loggregator有是数据的中转站。数据可以来自应用和CloudFoundry的自身组件。和SysLog不同,Log根据APP分离,所以产生的数据是为APP服务,而不是为CloudFoundry系统本身服务。</p>
<p>引入了Loggregator后,用户在创建Service的时候,Service可以返回一个SysLog URL。当该Service绑定到某一个应用,该应用的Log会顺着这个URL源源不断流入。这个Service可以说Splunk也可以说Pivotal Analytics. Heroku也有了这个机制。用户的大数据应用就可以无缝接入了。</p>
<p>Loggregator提供推(SysLog),拉(WebScoket)两种方式来获得数据。新的CF CLI就是使用Loggregator的WebSocket来获得APP的Log信息。</p>
<h2>部署-MicroCFv2福利</h2>
<p>不避讳的说,部署CloudFoundry v2的难度大于v1。</p>
<p>在v1中有dev_setup,提供一个基于Chef的一键脚本可以轻松部署。而v2中依赖BOSH,一个一站式的解决方案。可以将CloudFoundry部署在VSphere,OpenStack和AWS上。</p>
<p>目前看来有三种部署方式</p>
<ul>
<li>使用BOSH,BOSH比较重,运行起来就要费一些心力。但运转起来后可以提供健康监控,扩容的支持。</li>
<li>使用IaaS自带的部署机制,可以使用VSphere OVF,OpenStack Heat,Aws Cloudformation等技术。部署方便,但绑定IaaS。</li>
<li>手动一步步安装。最灵活,也最费力。可以考虑和Puppet等机制结合。</li>
</ul>
<p>由于官方不再提供新版本dev_setup,试一试CloudFoundry的成本变得很高。笔者提供了一个<a href="http://pan.baidu.com/s/1sj6jxd7">MicroCFv2镜像</a>,请使用7-zip解压</p>
<p><strong>MicroCFv2下载</strong> (基于<a href="https://github.com/cloudfoundry/cf-release/tree/v154">v154</a>)</p>
<h3><span style="line-height: 1.5em;">运行MicroCF</span></h3>
<ol>
<li>安装<a href="http://www.vmware.com/cn/products/player/">VMware Player</a>
</li>
<li>下载<a href="http://pan.baidu.com/s/1sj6jxd7">MicroCFv2</a>
</li>
<li>使用该镜像启动一台虚拟机</li>
<li>使用用户名/密码(admin/admin)登录</li>
</ol>
<p>检查网络,正常情况下虚拟机会通过DHCP获得IP地址。记下IP。编译应用需要访问外网。</p>
<pre lang="bash">admin@atsg2-sh199:~/env$ ifconfig
eth0 Link encap:Ethernet HWaddr 00:50:56:98:7f:0a
inet addr:10.32.170.199 Bcast:10.32.170.255 Mask:255.255.255.0
</pre>
<h3>部署一个Java APP</h3>
<pre lang="bash">admin@atsg2-sh199:~$ cd /home/admin
admin@atsg2-sh199:~$ cf login
API endpoint> api.cf.com
Username> admin
Password> admin
admin@atsg2-sh199:~$ cf push helloworld -p helloworld.war
App started
urls: helloworld.cf.com
state since cpu memory disk
#0 running 2014-02-06 11:52:18 PM 0.0% 60.8M of 1G 95.1M of 1G
admin@atsg2-sh199:~$ curl helloworld.cf.com</pre>
<h1>helloworld</h1>
<pre lang="bash"> </pre>
<h3>创建一个Service</h3>
<pre lang="bash">admin@atsg2-sh199:~/env$ cf create-user-provided-service oracle-db-mine -p '{"username":"admin","password":"pa55woRD"}'
OK
admin@atsg2-sh199:~/env$ cf bind-service helloworld oracle-db-mine
OK
</pre>
<h3>部署一个Ruby APP,并查看环境变量</h3>
<p>部署Ruby APP,需要访问网络。<br>这个APP可以显现他自己的所有环境变量。</p>
<pre lang="bash">admin@atsg2-sh199:~$ cd /home/admin/env
admin@atsg2-sh199:~/env$sudo bundle install
admin@atsg2-sh199:~/env$ cf push
requested state: started
urls: env.cf.com
state since cpu memory disk
#0 running 2014-02-07 12:14:18 AM 0.0% 18.1M of 128M 53.2M of 1G
admin@atsg2-sh199:~/env$ cf bind-service env oracle-db-mine
OK
admin@atsg2-sh199:~/env$ cf restart env
OK
admin@atsg2-sh199:~/env$ curl env.cf.com
...
VCAP_APP_HOST:
{ "user-provided": [
{ "name": "oracle-db-mine",
"label": "user-provided",
"tags": [],
"credentials": {
"password": "pa55woRD",
"username": "admin"
},
"syslog_drain_url": ""
}]}
...
</pre>
<h3>设置浏览器</h3>
<p>你可以使用浏览器访问你部署的应用。需要给浏览器设置HTTP代理。IP为MicroCFv2的IP,端口是8123.如:<br><br></p>
<p>这样就可以使用浏览器了。<br><br></p>
<p>使用愉快。如果遇到问题,可以联系我。</p> </div>
<!-- .entry-content -->
<footer class="entry-meta">
<span class="cat-links">
文章分类 <a href="./category/%e6%8a%80%e6%9c%af/index.html" rel="category tag">软件技术</a> </span>
<span class="sep"> | </span>
<span class="taglinks">
标签: <a href="./tag/cloudfoundry/index.html" rel="tag">CloudFoundry</a>, <a href="./tag/micro-cloudfoundry/index.html" rel="tag">Micro CloudFoundry</a> </span>
<span class="sep"> | </span>
<span class="comments-link"><a href="./cloudfoundry-v2-with-microcf/index.html#comments">5 评论</a></span>
<span class="sep"> | </span>
</footer>
<!-- #entry-meta -->
</article><!-- #post-27189 -->
<article id="post-26821" class="post-26821 post type-post status-publish format-standard hentry category-5 tag-docker tag-paas">
<header class="entry-header">
<h2 class="entry-title">
<a href="./docker-paas-for-any-application/index.html" title="连结到Docker能够运行任何应用的“PaaS”云" rel="bookmark">Docker能够运行任何应用的“PaaS”云</a>
</h2>
<div class="entry-meta">
在 <a href="./docker-paas-for-any-application/index.html" title="下午3:35" rel="bookmark">
<time class="entry-date updated" datetime="2013-09-17T15:35:09+08:00">2013年9月17日</time>
</a> 上公布 <span class="byline"> 作者为 <span class="author vcard">
<a class="url fn n" href="./author/yankay/index.html" title="查看 yankay 的所有文章" rel="author">yankay</a>
</span>
</span> </div>
<!-- .entry-meta -->
</header>
<!-- .entry-header -->
<div class="entry-content">
<h3>Docker 简介</h3>
<p><a href="http://www.docker.io/">Docker </a>是一个开源可以将<strong>任何应用</strong>包装在”LXC容器”中运行的工具。如果说VMware,KVM包装的虚拟机,Docker包装的是应用。是一个实至名归的PaaS。</p>
<p>当应用被打包成Docker Image后,部署和运维就变得极其简单。可以使用<strong>统一的方式 </strong>来下载,启动,扩展,删除,迁移。</p>
<p><img loading="lazy" decoding="async" class="alignnone size-medium wp-image-27237" src="http://47.100.65.109/wp-content/uploads/2013/09/homepage-docker-logo-300x248.png" alt="" width="300" height="248" srcset="./wp-content/uploads/2013/09/homepage-docker-logo-300x248.png 300w, ./wp-content/uploads/2013/09/homepage-docker-logo.png 400w" sizes="(max-width: 300px) 100vw, 300px"></p>
<p>Dock可以用来:</p>
<ul>
<li>自动化打包和部署任何应用</li>
<li>创建一个轻量级私有PaaS云</li>
<li>搭建开发测试环境</li>
<li>部署可扩展的Web应用</li>
</ul>
<p>Docker是开源的,可以在<a href="https://github.com/dotcloud/docker/">GitHub</a>上访问其代码,提供Restful接口。他的贡献者是一个非常流行的PaaS云提供商 <a href="https://dotcloud.com/">https://dotcloud.com/</a></p>
<h3>PaaS 的核心价值</h3>
<h4>遗失的方向 – 绝大部分应用竟然不能无缝迁移到主流PaaS上</h4>
<p>云计算发展多年,分为IaaS,PaaS和SaaS。其中PaaS(平台即服务)最为不愠不火。笔者因为,最大的原因是PaaS给人(开发,运维,老板)带来的价值不够多,私有PaaS门槛高!最大的问题在于绝大部分应用竟然不能无缝迁移到PaaS上。</p>
<p>Heroku是最流行的公有PaaS云。很廉价好用,可是大部分应用都无法部署。每个应用只能监听一个HTTP端口,应用之间不能交互。他可以为你自动扩展和负载均衡,但其实没得选择,只要使用Heroku就必须接受限制。好歹Heroku支持绝大部分平台如Java,Python。相比之下,GAE更甚,只支持三个平台,不能访问文件系统,也不能启动子进程。</p>
<p>CloudFoundry是比较流行的私有PaaS云。限制和Heroku一样多,部署比较复杂。为此他甚至有一个量身定制的部署工具BOSH。有多难用,用过的人都知道。这个不能怪开发人员,他定义的PaaS本来就这么复杂。</p>
<h4>PaaS要实现开发人和运维人的梦</h4>
<h5>开发人的梦 – 自在的运行环境,无限的资源</h5>
<p>开发人希望专注于程序逻辑。有自由自在的运行环境,有丰富的外部资源如各种中间件。至少不要为什么 端口监听数目,通信协议限制 这些事情所困扰。</p>
<h5>运维人的梦 – 没有故障和重复的事,减少等待</h5>
<p>运维天天处理故障,如果千千万应用都能以同样的方式部署,运维。那么故障的处理就简单多了,重复的事情也会变少。下载部署,安装依赖,这些事情都太过繁琐耗时了。</p>
<h5>Docker功能</h5>
<p>Docker可以让开发和运维都变得简单。</p>
<p>开发者不必要像使用一般PaaS一样在充满着限制的条件下开发应用,可以就如同平常一样,自由的使用各种资源。老子说“太上下知有之 ,其次誉之,其次侮之”。Dock对于开发者就是“下知有之”的状态。</p>
<p>爽的人是运维。要使用Docker,需要在机器上安装Docker Engine,</p>
<ol>
<li>创建一个Container。实际上是一个Linux Container,Docker会将网络,存储这些事情都配好。</li>
<li>下载应用并安装。比如可以用sudo apt-get install mysql-server 来安装一个MySQL。并配置一些参数什么的。</li>
<li>打包上传Image。Docker可以将这个Linux Container打包成Image,启动脚本也在其中。并上传至Image Registry中。这个Image仅仅包括你修改的<strong>增量部分</strong>,所以体积比较小。</li>
<li>一条命令跑起来。使用Docker Run 一条命令可以从Image Registry中下载Image 并跑起来。</li>
</ol>
<p>需要重启的时候,只要重启Container。需要迁移的时候,只要迁移Container。一切干干净净。</p>
<h4>PaaS,IaaS术业有专攻</h4>
<p>IaaS普遍使用虚拟机,开销较大。Docker明显更轻量。笔者认为IaaS和PaaS各有专攻,PaaS去专注于安全级别的隔离是没有意义的,IaaS也不应该去感知到应用。一个公有云中,可以让每个租户使用不同的虚拟机,虚拟网络来做到安全和资源上的隔离。再通过PaaS统一运维,管理计算资源。</p>
<p>没有必要让每个应用都专享一台虚拟机,这样开销太大。但在安全敏感的环境中,每个租户使用不同的虚拟机是合理的。</p>
<h3>使用Docker</h3>
<h4>在线尝试</h4>
<p>使用Docker最便捷的方式莫过于 <strong>在线尝试</strong>: <a href="http://www.docker.io/gettingstarted/#">http://www.docker.io/gettingstarted/#</a></p>
<p>完成了这个在线的教材,相信你对Docker已经基本玩转了。</p>
<h4>在Ubuntu中安装Docker</h4>
<p>现在Docker支持两个Ubuntu版本:</p>
<ul>
<li><a href="http://docs.docker.io/en/latest/installation/ubuntulinux/#ubuntu-precise"><em>Ubuntu Precise 12.04 (LTS) (64-bit)</em></a></li>
<li><a href="http://docs.docker.io/en/latest/installation/ubuntulinux/#ubuntu-raring"><em>Ubuntu Raring 13.04 (64 bit)</em></a></li>
</ul>
<p>有两个依赖</p>
<ul>
<li>Linux kernel 3.8 (read more about <a href="http://docs.docker.io/en/latest/installation/kernel/#kernel"><em>Kernel Requirements</em></a>)</li>
<li>AUFS 文件系统</li>
</ul>
<p>所以需要确认下您的操作系统,安装依赖并重启:</p>
<pre class="lang:sh decode:true"># Add the PPA sources to your apt sources list.
sudo apt-get install python-software-properties && sudo add-apt-repository ppa:dotcloud/lxc-docker
# Update your sources
sudo apt-get update
# Install, you will see another warning that the package cannot be authenticated. Confirm install.
sudo apt-get install lxc-docker</pre>
<p>安装Docker并重启:</p>
<pre class="lang:sh decode:true"># Add the PPA sources to your apt sources list.
sudo apt-get install python-software-properties && sudo add-apt-repository ppa:dotcloud/lxc-docker
# Update your sources
sudo apt-get update
# Install, you will see another warning that the package cannot be authenticated. Confirm install.
sudo apt-get install lxc-docker</pre>
<p>使用Docker,下载一个Ubuntu Image,并创建一个Container,在其中运行Bash</p>
<pre class="lang:sh decode:true"># download the base 'ubuntu' container and run bash inside it while setting up an interactive shell
sudo docker run -i -t ubuntu /bin/bash
# type 'exit' to exit</pre>
<p>成功,你已经玩转Docker了!!</p>
<h4>Docker Run的时候发生了什么?</h4>
<p>当用户执行Docker run的时候,发生了这些事情:</p>
<ol>
<li>Docker CLI 调用 Docker Engine的Restful API。默认情况下,Docker Engine是监听在一个Unix Socket上的,当然也可以监听在TCP端口上。</li>
<li>从<a href="https://index.docker.io/">docker index</a>下载一个Ubuntu Image。<a href="https://index.docker.io/">docker index</a>是一个荟萃Docker Image的地方,就像一个Repository.你也可以构建自己的私有Repository。</li>
<li>分配文件系统。文件系统是AUFS,这是一种“增量文件系统”,你做的修改都可以以增量的方式保存。因此Docker Image可以很小。</li>
<li>Mount文件系统</li>
<li>创建网络端口。Docker使用Linux Bridge和Linux Network NameSpace来配置网络。</li>
<li>配置IP地址。给刚刚创建的虚拟网卡配一个内部IP。这个IP不重要,因为Docker是通过静态NAT来对外保留TCP/UDP端口的。</li>
<li>在LXC中执行命令,这个例子中命令就是 “/bin/bash”</li>
<li>截取“/bin/bash”的输入输出流到Terminal,和你交互</li>
</ol>
<h3><span style="font-size: 1.17em;">Dock详解</span></h3>
<h4>在Docker中运行Redis</h4>
<p>创建一个Docker Container</p>
<pre class="lang:sh decode:true">sudo docker run -i -t ubuntu /bin/bash</pre>
<p>安装Redis .</p>
<pre class="lang:sh decode:true">apt-get update
apt-get install redis-server
exit</pre>
<p>拍个快照,创建你自己的Docker Redis Image</p>
<pre class="lang:sh decode:true">docker ps -a # grab the container id (this will be the first one in the list)
docker commit <container_id> <your username>/redis</pre>
<p>运行Redis。-d 是指后台运行,使用你刚刚创建的Image。</p>
<pre class="lang:sh decode:true">sudo docker run -d -p 6379 <your username>/redis /usr/bin/redis-server</pre>
<p>使用redis-cli访问</p>
<pre class="lang:sh decode:true">sudo docker ps # grab the new container id
sudo docker inspect <container_id> # grab the ipaddress of the container
redis-cli -h <ipaddress> -p 6379
redis 10.0.3.32:6379> set docker awesome
OK
redis 10.0.3.32:6379> get docker
"awesome"
redis 10.0.3.32:6379> exit</pre>
<h4> 文件系统</h4>
<p>一般来说,要Linux需要两种文件系统</p>
<ol>
<li>boot file system (bootfs)</li>
<li>root file system (rootfs)</li>
</ol>
<p>bootfs包含有bootloader。用户从来不会更改bootfs。事实上,当机器启动结束后,kernel会卸载掉这个bootfs。</p>
<p>rootfs就是我们通常看到了Linux文件目录,包括 <tt>/dev, /proc, /bin, /etc,/lib, /usr,</tt> 和<tt>/tmp等等。不同的Linux发行版的rootfs是不一样的,软件包结构也是不同的。Docker通过管理rootfs,可以在同时运行多个Linux发行版。</tt></p>
<p>当传统Linux启动的时候,rootfs是只读的,检查完整性后会转化成可读写状态。</p>
<p>当Docker挂载rootfs的时候,也是只读的。但是他并没有把它转化为可读写状态,而且在其上使用 <a href="http://en.wikipedia.org/wiki/Union_mount">union mount</a> 来加一层,创建一个可读写的文件系统。原理的rootfs还是只读的,数据被写入新的空间。Docker称之为”层”,数据可以这样一层一层叠加起来。</p>
<p>最初的时候,最顶层中什么数据也没有,当进程创建修改文件的时候,数据就会保存在最顶层。底层的文件系统没有丝毫改变。</p>
<p>当导出Image的时候,其实就是导出最顶层而已。</p>
<p>由于底层的只读的,多个Docker Container可以共享,提高的文件系统的使用效率。</p>
<h3>Docker生态环境</h3>
<p>Docker是开源的,提供完善的Restful接口,设计简洁,直戳痛点。但是因此比较简单,没有华丽的功能。凤栖梧桐,以Docker为树干,衍生出许多优秀的项目。</p>
<ul>
<li>
<strong><a href="https://github.com/progrium/dokku">dokku</a> </strong>100行BASH的微Heroku。包含了一个PaaS的基本功能</li>
<li>
<strong><a href="https://github.com/ehazlett/shipyard">shipyard</a></strong> Docker管理界面,提供多Host,创建Container,查看Image等功能</li>
<li>
<strong><a href="https://github.com/dotcloud/openstack-docker">openstack-docker</a></strong> Docker和OpenStack集成,可以使用Nova和Glance来控制</li>
<li>
<strong><a href="https://github.com/ptone/jiffylab">jiffylab</a></strong>教学用Python和Unix Shell平台</li>
<li>
<strong><a href="http://www.memcachedasaservice.com/">BYO SAAS</a></strong> Memcached as a Service</li>
<li>
<strong><a href="https://github.com/crosbymichael/dockerui">Dockerui</a></strong> Docker管理界面</li>
</ul>
</div>
<!-- .entry-content -->
<footer class="entry-meta">
<span class="cat-links">
文章分类 <a href="./category/%e6%8a%80%e6%9c%af/index.html" rel="category tag">软件技术</a> </span>
<span class="sep"> | </span>
<span class="taglinks">
标签: <a href="./tag/docker/index.html" rel="tag">Docker</a>, <a href="./tag/paas/index.html" rel="tag">PaaS</a> </span>
<span class="sep"> | </span>
<span class="comments-link"><a href="./docker-paas-for-any-application/index.html#comments">9 评论</a></span>
<span class="sep"> | </span>
</footer>
<!-- #entry-meta -->
</article><!-- #post-26821 -->
<article id="post-27005" class="post-27005 post type-post status-publish format-aside hentry category-7 category-5 tag-scala post_format-post-format-aside">
<header class="entry-header">
<h2 class="entry-title">
<a href="./scala-tour-choiceness/index.html" title="连结到Scala Tour – 精选" rel="bookmark">Scala Tour – 精选</a>
</h2>
<div class="entry-meta">
在 <a href="./scala-tour-choiceness/index.html" title="上午2:55" rel="bookmark">
<time class="entry-date updated" datetime="2013-05-02T02:55:26+08:00">2013年5月2日</time>
</a> 上公布 <span class="byline"> 作者为 <span class="author vcard">
<a class="url fn n" href="./author/yankay/index.html" title="查看 yankay 的所有文章" rel="author">yankay</a>
</span>
</span> </div>
<!-- .entry-meta -->
</header>
<!-- .entry-header -->
<div class="entry-content">
<p>5月1日是劳动的日子,笔者做了一个学习Scala精彩特性的网站<a title="scala-tour" href="http://zh.scala-tour.com/" target="_blank" rel="noopener">Scala-Tour</a>。在学习Scala是时候,遇到很多令人激动的特性,主要函数式编程和并发。相比下Java已经老态龙钟,步履躇跚。或许Scala不会成为替代Java语言,但的确给后来者设立了标杆。所以做了这个网站,顺着一个一个例子,由浅入深,由表及里。逐渐学会Scala,尽管不会因此成为一个熟练Scala的开发者,但是对函数式编程的也会相当了然。这篇文章精选了Scala-Tour上了一些章节,想快速了解的朋友可以看看这篇文章,当然想详细看就上上<a title="scala-tour" href="http://zh.scala-tour.com/" target="_blank" rel="noopener">Scala-Tour</a>吧。<br>
<img loading="lazy" decoding="async" class="alignnone size-medium wp-image-27241" src="http://47.100.65.109/wp-content/uploads/2013/05/scala-300x137.png" alt="" width="300" height="137" srcset="./wp-content/uploads/2013/05/scala-300x137.png 300w, ./wp-content/uploads/2013/05/scala.png 332w" sizes="(max-width: 300px) 100vw, 300px"></p>
<h3>不再需要Close</h3>
<p>在Java里面,使用完资源(文件句柄,数据库连接)等之后,必须手动Close。否则发生泄漏后,程序只有被迫重启。Scala可以通过函数式实现自动close。</p>
<pre lang="scala">import scala.reflect.io.File
import java.util.Scanner
def withScanner(f: File, op: Scanner => Unit) = {
val scanner = new Scanner(f.bufferedReader)
try {
op(scanner)
} finally {
scanner.close()
}
}
withScanner(File("/proc/self/stat"),
scanner => println("pid is " + scanner.next()))</pre>
<p>这个例子是从/proc/self/stat文件中读取当前进程的pid。withScanner封装了try-finally块,所以调用者不用再close。</p>
<h3>按名称传递参数</h3>
<p>我们熟悉的参数传递方式是按值传递。按名称传递的方式,可以理解为直接传递参数名字,等到实际调用的时候,再去取值。在Java代码中,往往充斥着if(log.isDebug()){log.debug(…)}这样语句。之前的if调用是很有必要的,因为在之后的debug语句中往往有字符串拼接的操作。在不需要打Log的时候,字符串拼接也有可能发生异常抛出。而Scala可以通过按名称传递解决这个问题,这样就不再需要if(log.isDebug())这样的语句了。</p>
<pre lang="scala">val logEnable = false
def log(msg: => String) =
if (logEnable) println(msg)
val MSG = "programing is running"
log(MSG + 1 / 0)</pre>
<h3>鸭子类型</h3>
<p>“走起来像鸭子,叫起来像鸭子,就是鸭子。”这个例子中使用{ def close(): Unit }作为参数类型。因此任何含有close()的函数的类都可以作为参数。这样的做法比使用接口要好很多,因为可以不引入任何依赖。这个withClose方法单独编译,随处使用。</p>
<pre lang="scala">def withClose(closeAble: { def close(): Unit }, op: { def close(): Unit } => Unit) {
try {
op(closeAble)
} finally {
closeAble.close()
}
}
class Connection {
def close() = println("close Connection")
}
val conn: Connection = new Connection()
withClose(conn, conn =>
println("do something with Connection"))</pre>
<h3>Trait</h3>
<p>Traits就像是有函数体的Interface,使用with关键字来混入。单个Traits就像是一块乐高积木,一个插件。就像下面的JsonAble,当使用一个对象的时候,可以随时随地把它插在他上面。这个对接就具备了toJson的能力。不用创建一个类,或者写组合的代码,非常干脆。这样也可以使代码有很高的正交性。不再会为了一个很小的需求,去修改一个被广泛使用的类。</p>
<pre lang="scala">trait ForEachAble[A] {
def iterator: java.util.Iterator[A]
def foreach(f: A => Unit) = {
val iter = iterator
while (iter.hasNext)
f(iter.next)
}
}
trait JsonAble {
def toJson() =
scala.util.parsing.json.JSONFormat.defaultFormatter(this)
}
val list = new java.util.ArrayList[Int]() with ForEachAble[Int]
list.add(1); list.add(2)
println("For each: "); list.foreach(x => println(x))
//println("Json: " + list.toJson())</pre>
<h3>函数式真正的威力</h3>
<p>通过将函数作为参数,可以使程序极为简洁。 函数式除了能简化代码外,更重要的是他关注的是Input和Output,函数本身没有副作用。 就是Unix pipeline一样,简单的命令可以组合在一起。 List的filter方法接受一个过滤函数,返回一个新的List 如果你喜欢Unix pipeline的方式,你一定也会喜欢函数式编程。 这个例子是用函数式的代码模拟“cat file | grep ‘warn’ | grep ‘2013’ | wc”的行为。相比于Ruby等动态语言,这威力来自于科学而不是魔法</p>
<pre lang="scala">val file = List("warn 2013 msg", "warn 2012 msg", "error 2013 msg", "warn 2013 msg")
println("cat file | grep 'warn' | grep '2013' | wc : "
+ file.filter(_.contains("warn")).filter(_.contains("2013")).size)</pre>
<h3>再见 NullException</h3>
<p>每个Java程序员都被NullException折磨过。因为Java中每个对象都可能为Null,所以要么到处检查null的问题,要么到处try/cache。<br>
Scala提供了Option机制来解决,代码中不断检查null的问题。这个例子包装了getProperty方法,使其返回一个Option。 这样就可以不再漫无目的地null检查。只要Option类型的值即可。使用pattern match来检查是常见做法。也可以使用getOrElse来提供当为None时的默认值。给力的是Option还可以看作是最大长度为1的List,List的强大功能都可以使用。<br>
不是每个对象都可以为Null了,只有Option可以为None。这样的做法显示区分了可能为Null的情况,可以和NullException说再见了。</p>
<pre lang="scala">def getProperty(name: String): Option[String] = {
val value = System.getProperty(name)
if (value != null) Some(value) else None
}
val osName = getProperty("os.name")
osName match {
case Some(value) => println(value)
case _ => println("none")
}
println(osName.getOrElse("none"))
osName.foreach(print _)</pre>
<h3>并行集合</h3>
<p>这个例子是访问若干URL。但确可以并行访问,比非并行的做法可以快一倍。要想让访问并行,只要调用List.par就可以了。</p>
<pre lang="scala">val urls = List("http://scala-lang.org",
"https://github.com/yankay/scala-tour")
def fromURL(url: String) = scala.io.Source.fromURL(url)
.getLines().mkString("\n")
val t = System.currentTimeMillis()
urls.par.map(fromURL(_))
println("time: " + (System.currentTimeMillis - t) + "ms")</pre>
<p>是不是非常的简单?并行集合支持大部分集合的功能。不增加程序复杂性,却能大幅提高并发的能力。</p>
<h3>远程Actor</h3>
<p>Actor是并发模型,也使用于分布式。这个例子创建一个时间服务器,通过alive来监听TCP端口,register来注册自己。调用时通过select创建client。其余使用方式和普通Actor一样。<br>
将单机并发和分布式抽象成一种模型。简化了程序复杂性。虽然多核编程并不广泛,但调用外部接口的情况越来越多。Actor模型非常适用于这样的异步环境。</p>
<pre lang="scala">import scala.actors.remote.RemoteActor._
import scala.actors.Actor._
import scala.actors.remote.Node
val port = 31241
val echoServer = actor {
alive(port)
register('echoServer, self)
loop {
react {
case msg => {
reply("replay " + msg)
}
}
}