-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfeed.xml
More file actions
1836 lines (1590 loc) · 139 KB
/
feed.xml
File metadata and controls
1836 lines (1590 loc) · 139 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Hello, World!</title>
<link href="http://terryoy.github.io/feed.xml" rel="self" />
<link href="http://terryoy.github.io/" />
<updated>2020-02-01T10:09:37+08:00</updated>
<id>http://terryoy.github.io/</id>
<entry>
<title type="html"><![CDATA[How to Write a Shell Script?]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2019/07/how-to-write-a-shell-script-.html"/>
<published>2019-07-01T18:11:00+08:00</published>
<updated>2020-02-01T10:09:36+08:00</updated>
<id>http://terryoy.github.io/2019/07/how-to-write-a-shell-script-.html</id>
<category scheme="http://terryoy.github.io/tag/#shell" term="shell" label="shell" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <p>Finnally, I've done it! Wow, it took me 3 hours to explore the ability of bash scripts.</p>
<p>I was trying to write a shell script to help me create this blog article, in an interactive way. </p>
<p>The blog articles are organized in a directory structure: <code>_content/{year}/{article-name-slug.md}</code>, and it also has a template to write the meta info for this article, which is like:</p>
<pre><code># How to Write a Shell Script?
- date: 2019-07-01 18:11
- tags: shell
- category: guides
-------</code></pre>
<p>So the basic idea is like this:</p>
<ul>
<li>I want to create the page where I could simply input the title, tags, and category</li>
<li>the date time is generated by the script</li>
<li>the file path is determined by the information I input and the date</li>
<li>the file name is slugified</li>
<li>all the information is filled in the template</li>
<li>use vim to open the file and filled the initial content with the template</li>
</ul>
<p>All the functions I needed and searched are listed below:</p>
<ul>
<li>prompt info and read values from user input. using <code>echo</code> and <code>read</code> command</li>
<li>list the tags and categories. using <code>ls -p</code>, <code>tr</code>, <code>sort</code>, and <code>column</code></li>
<li>making the steps as functions</li>
<li>fill template file with environmental variables. using <code>cat</code>, <code>echo</code> and <code>eval</code></li>
<li>creatign temporary file to hold the generated content from the template. using <code>$RANDOM</code> env variable for a random number.</li>
<li>fill the vi editing content after entering the editor. using <code>vi <filename> -c "read <tmpfile>"</code></li>
</ul>
<p>So the final example of the shell script can be found <a href="https://github.com/terryoy/terryoy.github.io/blob/master/_newpage.sh">here</a></p>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Setup ARM Development Environment with QEMU]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2018/04/setup_arm_development.html"/>
<published>2018-04-21T23:26:00+08:00</published>
<updated>2020-02-01T10:09:36+08:00</updated>
<id>http://terryoy.github.io/2018/04/setup_arm_development.html</id>
<category scheme="http://terryoy.github.io/tag/#linux" term="linux" label="linux" />
<category scheme="http://terryoy.github.io/tag/#qemu" term="qemu" label="qemu" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <h3 id="toc_0">1. Clone the kernel repository</h3>
<div class="highlight"><pre><span></span>$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
<span class="c1"># or just download the package from the mirror</span>
$ wget https://mirror.tuna.tsinghua.edu.cn/kernel/v4.x/linux-4.4.1.tar.xz
</pre></div>
<h3 id="toc_1">2. Install the Cross Compiling Toolchain</h3>
<div class="highlight"><pre><span></span>$ sudo apt-get install gcc-arm-linux-gnueabi
<span class="c1"># another option is "arm-linux-gnueabihf" but we use "gcc-arm-gnueabi" here</span>
</pre></div>
<h3 id="toc_2">3. Make the first compile</h3>
<p>We're emulating the vexpress Cortex A9 for demo.</p>
<div class="highlight"><pre><span></span>$ <span class="nb">export</span> <span class="nv">ARCH</span><span class="o">=</span>arm
$ <span class="nb">export</span> <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabi-
$ make vexpress_defconfig
$ make zImage -j8
$ make modules -j8
$ make dtbs
</pre></div>
<h3 id="toc_3">4. Install QEMU</h3>
<div class="highlight"><pre><span></span>$ sudo apt-get install qemu
</pre></div>
<h3 id="toc_4">5. Make Root File System</h3>
<h3 id="toc_5">5.1 busybox</h3>
<div class="highlight"><pre><span></span>$ wget http://www.busybox.net/downloads/busybox-1.25.1.tar.bz2
$ tar xvf busybox-1.25.1.tar.bz2
$ make defconfig
$ make <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabi-
$ make install <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabi-
</pre></div>
<p>Then you find the executables in <code>_install</code> folder. Next we start to create the rootfs.</p>
<h3 id="toc_6">5.2 rootfs</h3>
<div class="highlight"><pre><span></span>$ sudo mkdir rootfs
$ sudo mkdir rootfs/lib
<span class="c1"># copy busybox to rootfs</span>
$ sudo cp _install/* -r rootfs/
<span class="c1"># copy arm libs to lib</span>
<span class="c1"># sudo cp -P /usr/arm-linux-gnueabi/lib/* rootfs/lib/</span>
</pre></div>
<h3 id="toc_7">5.3 Create 4 tty devices</h3>
<div class="highlight"><pre><span></span>$ sudo mkdir -p rootfs/dev
$ sudo mknod rootfs/dev/tty1 c <span class="m">4</span> <span class="m">1</span>
$ sudo mknod rootfs/dev/tty2 c <span class="m">4</span> <span class="m">2</span>
$ sudo mknod rootfs/dev/tty3 c <span class="m">4</span> <span class="m">3</span>
$ sudo mknod rootfs/dev/tty4 c <span class="m">4</span> <span class="m">4</span>
</pre></div>
<p>You can also create other folders in the image. (Reference: <a href="https://learningfromyoublog.wordpress.com/2016/04/05/131/">learningfromyoublog.wordpress.com/2016/04/05/131/</a>)</p>
<h3 id="toc_8">5.4 Make the Image</h3>
<div class="highlight"><pre><span></span><span class="c1"># creat an empty image</span>
$ dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>a9rootfs.ext3 <span class="nv">bs</span><span class="o">=</span>1M <span class="nv">count</span><span class="o">=</span><span class="m">32</span>
<span class="c1"># format to ext3</span>
$ mkfs.ext3 a9rootfs.ext3
<span class="c1"># copy files into the image</span>
$ sudo mkdir tmpfs
$ sudo mount -t ext3 a9rootfs.ext3 tmpfs/ -o loop
$ sudo cp -r rootfs/* tmpfs/
$ sudo umount tmpfs
</pre></div>
<h3 id="toc_9">6. Start QEMU with the Image</h3>
<div class="highlight"><pre><span></span><span class="c1"># open in current console</span>
$ qemu-system-arm -M vexpress-a9 -m 512M -dtb extra_folder/vexpress-v2p-ca9.dtb -kernel extra_folder/zImage -nographic -append <span class="s2">"root=/dev/mmcblk0 rw console=ttyAMA0"</span> -sd a9rootfs.ext3
<span class="c1"># open in new window(maybe GUI)</span>
$ qemu-system-arm -M vexpress-a9 -m 512M -dtb extra_folder/vexpress-v2p-ca9.dtb -kernel extra_folder/zImage -append <span class="s2">"root=/dev/mmcblk0 rw"</span> -sd a9rootfs.ext3
</pre></div>
<p>Now you enter the console of the emulator system. Press <code>Ctrl+A C</code> to exit to <code>(qemu)</code> console, or <code>Ctrl+A X</code> to exit..</p>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Learn to Use CMake to Compile Code]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2018/01/learn-to-use-cmake.html"/>
<published>2018-01-12T14:41:00+08:00</published>
<updated>2020-02-01T10:09:36+08:00</updated>
<id>http://terryoy.github.io/2018/01/learn-to-use-cmake.html</id>
<category scheme="http://terryoy.github.io/tag/#linux" term="linux" label="linux" />
<category scheme="http://terryoy.github.io/tag/#programming" term="programming" label="programming" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <p>I'm trying to use the Linux environment to develop C/C++ programs, but never really get on the path.</p>
<p>It's not the language that I don't understand, but the environment, the toolchain and how to configure a project in real life is my question. Linux have many programs developed in C/C++, but compiling them myself always out of my scope, which is blocking me from deeper understanding of Linux.</p>
<p>So here I'm reading a walkthrough to help myself making a C/C++ project work.</p>
<p><strong>CMake</strong> is said to be an OS and compiler independent build system. So you first write CMake configurations in any source directories, and then it can generate a native build environment that will compile source code, create libraries, generate wrappers and build executables in arbitrary combinations.</p>
<h3 id="toc_0">0. Build Essential</h3>
<p>First of all, if you want to compile anything in Linux, you should install the <code>build-essential</code> package first.</p>
<div class="highlight"><pre><span></span>$ sudo apt install build-essential
</pre></div>
<p>It contains all the common packages to build Debian packages, such as: g++, gcc, hurd, libc, dpkg, make, etc.</p>
<p>Next step let's install the CMake package:</p>
<div class="highlight"><pre><span></span>$ sudo apt install cmake
</pre></div>
<h3 id="toc_1">1. A Hello World and a CMakeLists.txt</h3>
<p>The minimal demo has two files. </p>
<p>A <code>hello.cpp</code> source file:</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"></span>
<span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
<span class="n">cout</span> <span class="o"><<</span> <span class="s">"Hello World"</span> <span class="o"><<</span> <span class="n">endl</span><span class="p">;</span>
<span class="k">return</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
<p>A <code>CMakeLists.txt</code> config file:</p>
<pre><code># Specify the minimum version for CMake
cmake_minimum_required(VERSION 2.8)
# Project's name
project(hello)
# Set the output folder where your program will be created
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
# The following folder will be included
include_directories("${PROJECT_SOURCE_DIR}")
# Compile the program to hello
add_executable(hello ${PROJECT_SOURCE_DIR}/hello.cpp)</code></pre>
<p>The three lines <code>cmake_minimum_required</code>, <code>project(hello)</code>, and <code>add_executable</code> are essential.</p>
<p>Run below two commands to compile the exectuatble:</p>
<div class="highlight"><pre><span></span><span class="c1"># Generate CMake configurations</span>
$ cmake -H. -Bbuild
<span class="c1"># Build the executable</span>
$ cmake --build build -- -j3
</pre></div>
<h3 id="toc_2">References</h3>
<p><a href="https://tuannguyen68.gitbooks.io/learning-cmake-a-beginner-s-guide/content/chap1/chap1.html">Learning CMake: A Beginner's Guide</a>
<a href="https://cmake.org/cmake-tutorial/">CMake Official Tutorial</a></p>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Networking in Docker]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2018/01/networking-in-docker.html"/>
<published>2018-01-12T11:41:00+08:00</published>
<updated>2020-02-01T10:09:36+08:00</updated>
<id>http://terryoy.github.io/2018/01/networking-in-docker.html</id>
<category scheme="http://terryoy.github.io/tag/#linux" term="linux" label="linux" />
<category scheme="http://terryoy.github.io/tag/#docker" term="docker" label="docker" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <p>After installed an Ubuntu container in my docker, now I'm trying to learn the networking tools in Ubuntu and Docker.</p>
<ol>
<li>Networking Tools in Ubuntu Again</li>
</ol>
<div class="highlight"><pre><span></span><span class="c1"># package for ifconfig(which is too old)</span>
$ apt install net-tools
<span class="c1"># newer package for networking</span>
$ apt install iproute2
<span class="c1"># ping command</span>
$ apt install iputils-ping
<span class="c1"># check network interface</span>
$ ifconfig
eth0 Link encap:Ethernet HWaddr <span class="m">02</span>:42:ac:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:5956 errors:0 dropped:0 overruns:0 frame:0
TX packets:3345 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:8376715 <span class="o">(</span><span class="m">8</span>.3 MB<span class="o">)</span> TX bytes:186204 <span class="o">(</span><span class="m">186</span>.2 KB<span class="o">)</span>
</pre></div>
<ol>
<li>Docker Commands for Networking</li>
</ol>
<p>There are three types of networks in docker, and the <code>bridge</code> network is by default presented in all docker instances.</p>
<div class="highlight"><pre><span></span><span class="c1"># List networks in Docker</span>
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a6bf46c2bc44 bridge bridge <span class="nb">local</span>
e3826e52e7e6 host host <span class="nb">local</span>
08a134ed472c none null <span class="nb">local</span>
<span class="c1"># Check docker's network detail</span>
$ docker network inspect bridge
<span class="o">[</span>
<span class="o">{</span>
<span class="s2">"Name"</span>: <span class="s2">"bridge"</span>,
<span class="s2">"Id"</span>: <span class="s2">"a6bf46c2bc44dc16523ac28edd5524fccef79b779ae52602c868001763cd21c4"</span>,
<span class="s2">"Created"</span>: <span class="s2">"2018-01-09T11:36:15.168104899Z"</span>,
<span class="s2">"Scope"</span>: <span class="s2">"local"</span>,
<span class="s2">"Driver"</span>: <span class="s2">"bridge"</span>,
<span class="s2">"EnableIPv6"</span>: false,
<span class="s2">"IPAM"</span>: <span class="o">{</span>
<span class="s2">"Driver"</span>: <span class="s2">"default"</span>,
<span class="s2">"Options"</span>: null,
<span class="s2">"Config"</span>: <span class="o">[</span>
<span class="o">{</span>
<span class="s2">"Subnet"</span>: <span class="s2">"172.17.0.0/16"</span>,
<span class="s2">"Gateway"</span>: <span class="s2">"172.17.0.1"</span>
<span class="o">}</span>
<span class="o">]</span>
<span class="o">}</span>,
<span class="s2">"Internal"</span>: false,
<span class="s2">"Attachable"</span>: false,
<span class="s2">"Ingress"</span>: false,
<span class="s2">"ConfigFrom"</span>: <span class="o">{</span>
<span class="s2">"Network"</span>: <span class="s2">""</span>
<span class="o">}</span>,
<span class="s2">"ConfigOnly"</span>: false,
<span class="s2">"Containers"</span>: <span class="o">{</span>
<span class="s2">"cfc178841a7940b6cbf43c8e0dbd7fb6672af3b3e8a9020632c75352685ec685"</span>: <span class="o">{</span>
<span class="s2">"Name"</span>: <span class="s2">"ubuntu"</span>,
<span class="s2">"EndpointID"</span>: <span class="s2">"8c14adc4a61eacdc8bd2b261d2af4f17c7a966d9fcfb8c61b5f9284fa2eded45"</span>,
<span class="s2">"MacAddress"</span>: <span class="s2">"02:42:ac:11:00:02"</span>,
<span class="s2">"IPv4Address"</span>: <span class="s2">"172.17.0.2/16"</span>,
<span class="s2">"IPv6Address"</span>: <span class="s2">""</span>
<span class="o">}</span>
<span class="o">}</span>,
<span class="s2">"Options"</span>: <span class="o">{</span>
<span class="s2">"com.docker.network.bridge.default_bridge"</span>: <span class="s2">"true"</span>,
<span class="s2">"com.docker.network.bridge.enable_icc"</span>: <span class="s2">"true"</span>,
<span class="s2">"com.docker.network.bridge.enable_ip_masquerade"</span>: <span class="s2">"true"</span>,
<span class="s2">"com.docker.network.bridge.host_binding_ipv4"</span>: <span class="s2">"0.0.0.0"</span>,
<span class="s2">"com.docker.network.bridge.name"</span>: <span class="s2">"docker0"</span>,
<span class="s2">"com.docker.network.driver.mtu"</span>: <span class="s2">"1500"</span>
<span class="o">}</span>,
<span class="s2">"Labels"</span>: <span class="o">{}</span>
<span class="o">}</span>
<span class="o">]</span>
</pre></div>
<h3 id="toc_0">3. Internal Networking</h3>
<p>By default, the container is connected within a local network(172.17.0.1/16) bridged to the host machine, host can access the net gateway ip <code>172.17.0.1</code>. The contianers should be able to access each other in the local network provided by this net gateway. When you use the command <code>docker network inspect bridge</code>, you could see the list of containers and their IPs assigned.</p>
<h4 id="toc_1">3.1 Accessing container's service by port mapping</h4>
<p>Some containers as Nginx provide a service through a local port, in which case you could use port forwarding by your local IP. For example, you can check this port forwarding by <code>docker port</code> command or just listing the containers:</p>
<div class="highlight"><pre><span></span><span class="c1"># list ports for container</span>
$ docker port nginx
<span class="m">80</span>/tcp -> <span class="m">0</span>.0.0.0:5000
<span class="c1"># list containers</span>
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cfc178841a79 ubuntu <span class="s2">"/bin/bash"</span> <span class="m">3</span> weeks ago Up <span class="m">4</span> hours ubuntu
0200f61f5d65 nginx <span class="s2">"nginx -g 'daemon of…"</span> <span class="m">2</span> months ago Up <span class="m">3</span> minutes <span class="m">0</span>.0.0.0:5000->80/tcp webserver
</pre></div>
<p>Now you can see there is a port mapping from <code>host:5000</code> to <code>container:80</code>.</p>
<p>By default, no port is opened for a container to host, you need to specify the port mapping at <code>docker run</code> command with <code>-p</code>.</p>
<pre><code># `-d` is when you needed it run as a daemon.
$ docker run nginx -d -p 5000:80 --name nginx nginx</code></pre>
<p>To open a port mapping for an existing container is very tricky. It is often said that you need to create another container instance based on the current just to open a port.</p>
<h4 id="toc_2">3.2 Creating a Network</h4>
<p>Now let's try something advanced. Let's create the different types of network one by one.</p>
<h5 id="toc_3">3.2.1 Bridge Network</h5>
<p>By default, the network you created will be a <code>bridged</code> network. You can add container to the network later. It creates a subnet and open only specific ports to the host to access service in the subnet, like NAT.</p>
<div class="highlight"><pre><span></span>$ docker network create gamezone
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
0fe8bfe5222d gamezone bridge <span class="nb">local</span>
<span class="c1"># if you want to remove the bridge network</span>
$ docker network rm gamezone
</pre></div>
<p>Now let's create an Ubuntu container called “gamecenter” which connects to the gamezone network and maps port 5000 to the docker host's 15000.</p>
<div class="highlight"><pre><span></span>$ docker create --name gamecenter <span class="se">\</span>
--network gamezone <span class="se">\</span>
--publish <span class="m">15000</span>:5000 <span class="se">\</span>
-t -i ubuntu /bin/bash
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8cf4e293aae9 ubuntu <span class="s2">"/bin/bash"</span> <span class="m">10</span> minutes ago Up <span class="m">10</span> minutes <span class="m">0</span>.0.0.0:15000->5000/tcp gamecenter
$ docker network inspect gamezone
<span class="o">[</span>
<span class="o">{</span>
<span class="s2">"Name"</span>: <span class="s2">"gamezone"</span>,
<span class="s2">"Id"</span>: <span class="s2">"9b6417528a0e4a37ab9818e185a8046af06b3a9ae0eba40a2e494087676b70c9"</span>,
<span class="s2">"Created"</span>: <span class="s2">"2018-06-09T15:24:43.6288314Z"</span>,
<span class="s2">"Scope"</span>: <span class="s2">"local"</span>,
<span class="s2">"Driver"</span>: <span class="s2">"bridge"</span>,
<span class="s2">"EnableIPv6"</span>: false,
<span class="s2">"IPAM"</span>: <span class="o">{</span>
<span class="s2">"Driver"</span>: <span class="s2">"default"</span>,
<span class="s2">"Options"</span>: <span class="o">{}</span>,
<span class="s2">"Config"</span>: <span class="o">[</span>
<span class="o">{</span>
<span class="s2">"Subnet"</span>: <span class="s2">"172.18.0.0/16"</span>,
<span class="s2">"Gateway"</span>: <span class="s2">"172.18.0.1"</span>
<span class="o">}</span>
<span class="o">]</span>
<span class="o">}</span>,
<span class="s2">"Internal"</span>: false,
<span class="s2">"Attachable"</span>: false,
<span class="s2">"Ingress"</span>: false,
<span class="s2">"ConfigFrom"</span>: <span class="o">{</span>
<span class="s2">"Network"</span>: <span class="s2">""</span>
<span class="o">}</span>,
<span class="s2">"ConfigOnly"</span>: false,
<span class="s2">"Containers"</span>: <span class="o">{</span>
<span class="s2">"8cf4e293aae932693f6769eea08665306485b17018999d8725f14b659e51c919"</span>: <span class="o">{</span>
<span class="s2">"Name"</span>: <span class="s2">"gamecenter"</span>,
<span class="s2">"EndpointID"</span>: <span class="s2">"6ca3d79c633520dbee752ab6b462404aa8507f8eb9f2b2cf840de2d3322d27bb"</span>,
<span class="s2">"MacAddress"</span>: <span class="s2">"02:42:ac:12:00:02"</span>,
<span class="s2">"IPv4Address"</span>: <span class="s2">"172.18.0.2/16"</span>,
<span class="s2">"IPv6Address"</span>: <span class="s2">""</span>
<span class="o">}</span>
<span class="o">}</span>,
<span class="s2">"Options"</span>: <span class="o">{}</span>,
<span class="s2">"Labels"</span>: <span class="o">{}</span>
<span class="o">}</span>
<span class="o">]</span>
$ docker start gamecenter
$ docker attach gamecenter
$ ifconfig
eth0 Link encap:Ethernet HWaddr <span class="m">02</span>:42:ac:12:00:02
inet addr:172.18.0.2 Bcast:172.18.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:20872 errors:0 dropped:0 overruns:0 frame:0
TX packets:8684 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:28266802 <span class="o">(</span><span class="m">28</span>.2 MB<span class="o">)</span> TX bytes:476241 <span class="o">(</span><span class="m">476</span>.2 KB<span class="o">)</span>
</pre></div>
<p>You can notice that the container “gamecenter” is running in the subnet of <code>172.18.0.1</code> currently. And we have open a port <code>15000</code> on the host, to map to gamecenter's port <code>5000</code>.</p>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Setup Arm Development Environment]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2017/12/setup_arm_development.html"/>
<published>2017-12-31T00:00:00+08:00</published>
<updated>2020-02-01T10:09:36+08:00</updated>
<id>http://terryoy.github.io/2017/12/setup_arm_development.html</id>
<category scheme="http://terryoy.github.io/tag/#linux" term="linux" label="linux" />
<category scheme="http://terryoy.github.io/tag/#misc" term="misc" label="misc" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <h3 id="toc_0">1. Clone the kernel repository</h3>
<div class="highlight"><pre><span></span>$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
<span class="c1"># or just download the package from the mirror</span>
$ wget https://mirror.tuna.tsinghua.edu.cn/kernel/v4.x/linux-4.4.1.tar.xz
</pre></div>
<h3 id="toc_1">2. Install the Cross Compiling Toolchain</h3>
<div class="highlight"><pre><span></span>$ sudo apt-get install gcc-arm-linux-gnueabi
<span class="c1"># another option is "arm-linux-gnueabihf" but we use "gcc-arm-gnueabi" here</span>
</pre></div>
<h3 id="toc_2">3. Make the first compile</h3>
<p>We're emulating the vexpress Cortex A9 for demo.</p>
<div class="highlight"><pre><span></span>$ <span class="nb">export</span> <span class="nv">ARCH</span><span class="o">=</span>arm
$ <span class="nb">export</span> <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabi-
$ make vexpress_defconfig
$ make zImage -j8
$ make modules -j8
$ make dtbs
</pre></div>
<h3 id="toc_3">4. Install QEMU</h3>
<div class="highlight"><pre><span></span>$ sudo apt-get install qemu
</pre></div>
<h3 id="toc_4">5. Make Root File System</h3>
<h3 id="toc_5">5.1 busybox</h3>
<div class="highlight"><pre><span></span>$ wget http://www.busybox.net/downloads/busybox-1.25.1.tar.bz2
$ tar xvf busybox-1.25.1.tar.bz2
$ make defconfig
$ make <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabi-
$ make install <span class="nv">CROSS_COMPILE</span><span class="o">=</span>arm-linux-gnueabi-
</pre></div>
<p>Then you find the executables in <code>_install</code> folder. Next we start to create the rootfs.</p>
<h3 id="toc_6">5.2 rootfs</h3>
<div class="highlight"><pre><span></span>$ sudo mkdir rootfs
$ sudo mkdir rootfs/lib
<span class="c1"># copy busybox to rootfs</span>
$ sudo cp _install/* -r rootfs/
<span class="c1"># copy arm libs to lib</span>
<span class="c1"># sudo cp -P /usr/arm-linux-gnueabi/lib/* rootfs/lib/</span>
</pre></div>
<h3 id="toc_7">5.3 Create 4 tty devices</h3>
<div class="highlight"><pre><span></span>$ sudo mkdir -p rootfs/dev
$ sudo mknod rootfs/dev/tty1 c <span class="m">4</span> <span class="m">1</span>
$ sudo mknod rootfs/dev/tty2 c <span class="m">4</span> <span class="m">2</span>
$ sudo mknod rootfs/dev/tty3 c <span class="m">4</span> <span class="m">3</span>
$ sudo mknod rootfs/dev/tty4 c <span class="m">4</span> <span class="m">4</span>
</pre></div>
<p>You can also create other folders in the image. (Reference: <a href="https://learningfromyoublog.wordpress.com/2016/04/05/131/">learningfromyoublog.wordpress.com/2016/04/05/131/</a>)</p>
<h3 id="toc_8">5.4 Make the Image</h3>
<div class="highlight"><pre><span></span><span class="c1"># creat an empty image</span>
$ dd <span class="k">if</span><span class="o">=</span>/dev/zero <span class="nv">of</span><span class="o">=</span>a9rootfs.ext3 <span class="nv">bs</span><span class="o">=</span>1M <span class="nv">count</span><span class="o">=</span><span class="m">32</span>
<span class="c1"># format to ext3</span>
$ mkfs.ext3 a9rootfs.ext3
<span class="c1"># copy files into the image</span>
$ sudo mkdir tmpfs
$ sudo mount -t ext3 a9rootfs.ext3 tmpfs/ -o loop
$ sudo cp -r rootfs/* tmpfs/
$ sudo umount tmpfs
</pre></div>
<h3 id="toc_9">6. Start QEMU with the Image</h3>
<div class="highlight"><pre><span></span><span class="c1"># open in current console</span>
$ qemu-system-arm -M vexpress-a9 -m 512M -dtb extra_folder/vexpress-v2p-ca9.dtb -kernel extra_folder/zImage -nographic -append <span class="s2">"root=/dev/mmcblk0 rw console=ttyAMA0"</span> -sd a9rootfs.ext3
<span class="c1"># open in new window(maybe GUI)</span>
$ qemu-system-arm -M vexpress-a9 -m 512M -dtb extra_folder/vexpress-v2p-ca9.dtb -kernel extra_folder/zImage -append <span class="s2">"root=/dev/mmcblk0 rw"</span> -sd a9rootfs.ext3
</pre></div>
<p>Now you enter the console of the emulator system. Press <code>Ctrl+A C</code> to exit to <code>(qemu)</code> console, or <code>Ctrl+A X</code> to exit..</p>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Exploring Ubuntu From Fundamentals(1)]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2017/12/get-to-know-the-core-ubuntu.html"/>
<published>2017-12-22T15:49:00+08:00</published>
<updated>2020-02-01T10:09:37+08:00</updated>
<id>http://terryoy.github.io/2017/12/get-to-know-the-core-ubuntu.html</id>
<category scheme="http://terryoy.github.io/tag/#linux" term="linux" label="linux" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <p>Recently I have installed docker on my mac. It's such a wonderful virtualized environment that I don't need to install a whole system image on VirtualBox to explore in Ubuntu. </p>
<p>The docker image of Ubuntu is somehow essential subset of packages which give you the system environment. It doesn't even have <code>vi</code> or the <code>lsb_release</code> command for you to read the distro version. So I want to take some notes while I'm exploring the fundamentals in Ubuntu.</p>
<h3 id="toc_0">1. System Info</h3>
<div class="highlight"><pre><span></span><span class="c1"># Check Ubuntu version</span>
$ cat /etc/issue
$ cat /etc/issue.net
Ubuntu <span class="m">16</span>.04.3 LTS
<span class="c1"># More information of Ubuntu</span>
$ cat /etc/os-release
<span class="nv">NAME</span><span class="o">=</span><span class="s2">"Ubuntu"</span>
<span class="nv">VERSION</span><span class="o">=</span><span class="s2">"16.04.3 LTS (Xenial Xerus)"</span>
<span class="nv">ID</span><span class="o">=</span>ubuntu
<span class="nv">ID_LIKE</span><span class="o">=</span>debian
<span class="nv">PRETTY_NAME</span><span class="o">=</span><span class="s2">"Ubuntu 16.04.3 LTS"</span>
<span class="nv">VERSION_ID</span><span class="o">=</span><span class="s2">"16.04"</span>
<span class="nv">HOME_URL</span><span class="o">=</span><span class="s2">"http://www.ubuntu.com/"</span>
<span class="nv">SUPPORT_URL</span><span class="o">=</span><span class="s2">"http://help.ubuntu.com/"</span>
<span class="nv">BUG_REPORT_URL</span><span class="o">=</span><span class="s2">"http://bugs.launchpad.net/ubuntu/"</span>
<span class="nv">VERSION_CODENAME</span><span class="o">=</span>xenial
<span class="nv">UBUNTU_CODENAME</span><span class="o">=</span>xenial
<span class="c1"># System Services</span>
$ service --status-all
<span class="o">[</span> - <span class="o">]</span> bootmisc.sh
<span class="o">[</span> - <span class="o">]</span> checkfs.sh
<span class="o">[</span> - <span class="o">]</span> checkroot-bootclean.sh
<span class="o">[</span> - <span class="o">]</span> checkroot.sh
<span class="o">[</span> - <span class="o">]</span> hostname.sh
<span class="o">[</span> ? <span class="o">]</span> hwclock.sh
<span class="o">[</span> - <span class="o">]</span> killprocs
<span class="o">[</span> - <span class="o">]</span> mountall-bootclean.sh
<span class="o">[</span> - <span class="o">]</span> mountall.sh
<span class="o">[</span> - <span class="o">]</span> mountdevsubfs.sh
<span class="o">[</span> - <span class="o">]</span> mountkernfs.sh
<span class="o">[</span> - <span class="o">]</span> mountnfs-bootclean.sh
<span class="o">[</span> - <span class="o">]</span> mountnfs.sh
<span class="o">[</span> ? <span class="o">]</span> ondemand
<span class="o">[</span> - <span class="o">]</span> procps
<span class="o">[</span> - <span class="o">]</span> rc.local
<span class="o">[</span> - <span class="o">]</span> sendsigs
<span class="o">[</span> - <span class="o">]</span> umountfs
<span class="o">[</span> - <span class="o">]</span> umountnfs.sh
<span class="o">[</span> - <span class="o">]</span> umountroot
<span class="o">[</span> - <span class="o">]</span> urandom
<span class="c1"># Supported Shells</span>
$ cat /etc/shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
</pre></div>
<p>I have install <code>vim</code> and <code>man-db</code> to acquire the ability of text editing and manual reading. Now let's check what packages we have installed.</p>
<div class="highlight"><pre><span></span>$ apt list --installed
<span class="c1"># or if you just want the count</span>
$ apt list --installed <span class="p">|</span> grep installed <span class="p">|</span> wc -l
<span class="c1"># or if you want to see a description of each pacakge</span>
$ dpkg-query -l
</pre></div>
<p>Now I can see that the essential packages to run my system has only <strong>116</strong> packages and <strong>62</strong> of them are libs.</p>
<h3 id="toc_1">2. Reading Manuals</h3>
<p>The most important documentation tool in Linux is <code>man</code>, another is <code>info</code> from package “texinfo”. And there are also something you can find in <code>/usr/share/doc</code>, although many packages just use it for change logs and copyright, but the readme part is sometimes helpful information.</p>
<p>The <code>man</code> command is in <code>man-db</code> package, and <code>info</code> is in <code>info</code> package.</p>
<h4 id="toc_2">2.1 Man pages</h4>
<p>Man pages are grouped the documents of packages into 8(or 9) sections.</p>
<ul>
<li>1 Executable programs or shell commands</li>
<li>2 System calls (functions provided by the kernel)</li>
<li>3 Library calls (functions within program libraries)</li>
<li>4 Special files (usually found in /dev)</li>
<li>5 File formats and conventions eg /etc/passwd</li>
<li>6 Games</li>
<li>7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)</li>
<li>8 System administration commands (usually only for root)</li>
<li>9 Kernel routines [Non standard]</li>
</ul>
<p>The numbers of sections you see here, are used to marked the pages when cross reference in man pages. For example, you can see “man(7)”, “mandb(8)”, etc. Sometimes there will be a same keyword in different sections. You can view all man pages of the same keyword, or specify which section you want to see, or search man pages by keyword.</p>
<div class="highlight"><pre><span></span><span class="c1"># view man page for man</span>
$ man man
<span class="c1"># view all "intro" in every section</span>
$ man -a intro
<span class="c1"># view "intro" in section 3</span>
$ man -s <span class="m">3</span> intro
<span class="c1"># list all man pages</span>
$ man -k .
<span class="c1"># list all man pages in section 5</span>
$ man -s <span class="m">5</span> -k .
<span class="c1"># list all man pages in section 5 match keyword 'systemd'</span>
$ man -s <span class="m">5</span> -k systemd
</pre></div>
<h4 id="toc_3">2.2 Info pages</h4>
<p>This kind of document is written in <a href="https://www.gnu.org/software/texinfo/">texinfo</a>, supported in Emacs, generated by <code>makeinfo</code>;</p>
<p>The texinfo format has node structure, and can export to different format such as HTML, etc. The <code>info</code> command more navigation methods to the document.</p>
<p>Read <a href="http://www.troubleshooters.com/linux/info.htm">here</a> about the keyboard interface.</p>
<h4 id="toc_4">2.3 Dcoumentation paths</h4>
<ul>
<li>/usr/share/man, folder for man pages of pacakges. They're separated into different sections man(1-9) according the pacakge categories.</li>
<li>/usr/share/info, folder for info pages, which is meant for providing more detail information, and it's generally used in GNU projects, but man pages are in much greater favour.</li>
<li>/usr/share/doc, folder for holding other document or refernces. Most packages contains only changelog and copyright info, some provided a README file, and some package provides templates or configuration files.</li>
</ul>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Getting Laravel Started]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2017/11/laravel-get-started.html"/>
<published>2017-11-24T10:37:00+08:00</published>
<updated>2020-02-01T10:09:36+08:00</updated>
<id>http://terryoy.github.io/2017/11/laravel-get-started.html</id>
<category scheme="http://terryoy.github.io/tag/#php" term="php" label="php" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <p>After I found that PHP7.1 is in-the-box with OSX, it motivates me to start learning PHP(a.k.a. “the best language in the world” :P) and give some try to small projects. What I got from my friend is that <a href="https://laravel.com/">Laravel</a> is the quite popular web framework for PHP. So now I setting up the development and deployment environment to get started.</p>
<h3 id="toc_0">1.Installing dependencies</h3>
<p>On my MBP desktop, it's recommended to use <a href="https://laravel.com/docs/5.5/valet">Valet</a> if you want just a small additional tools to run it, and connect to existing databases on the machine. Otherwise it would be good to use a virtualbox image <a href="https://laravel.com/docs/5.5/homestead">Homestead</a> to have an all-in-one setup for development.</p>
<p>While my Ubuntu 16 server, I would like to install dependencies by hand, so I could get familiar with what it takes to run Laravel. Now here's what I tried.</p>
<div class="highlight"><pre><span></span>$ sudo apt install php7.0 php7.0-cli php7.0-zip php7.0-mbstring php7.0-mbstring php7.0-xml
</pre></div>
<p>Then we need to install <a href="https://getcomposer.org">Composer</a> to install other php packages. It's like the <code>pip</code> to Python and the <code>npm</code> to NodeJS.</p>
<div class="highlight"><pre><span></span><span class="c1"># install to $HOME/bin</span>
$ <span class="nb">cd</span> ~
$ wget https://getcomposer.org/installer -o composer-setup.php
$ php composer-setup.php --install-dir<span class="o">=</span>bin --filename<span class="o">=</span>composer
<span class="c1"># (alternatively) You could try the one-line command bellow for default installation</span>
$ curl -s https://getcomposer.org/installer <span class="p">|</span> php
</pre></div>
<p>Then try the composer command to see if you have it.</p>
<div class="highlight"><pre><span></span>$ composer
</pre></div>
<h3 id="toc_1">2.Installing Laravel Valet</h3>
<p><strong>Valet</strong> is a lightweight solution for hosting Laravel in development, and only avaiable on OSX. It uses brew to install php7.1 and other dependencies, but first you need Composer to install Laravel Valet. So install the composer using the script above first.</p>
<p>After composer is installed, use it to download the Valet package.</p>
<div class="highlight"><pre><span></span>$ composer global require laravel/valet
</pre></div>
<p>After composer install the package, you should note about where it is installed. Because you need to set the $PATH environment variables to enable the command from the packages. On OSX, the executable programs are in <code>~/.composer/vendor/bin</code>, and on Ubuntu, the path might be <code>~/.config/composer/vendor/bin</code>.</p>
<p>Then you can use valet commands to manage your development environment.</p>
<h3 id="toc_2">3.Install Laravel</h3>
<p>Installing Laravel is similar to Valet. Use <code>composer</code> to download and install the package globally.</p>
<div class="highlight"><pre><span></span>$ composer global require <span class="s2">"laravel/installer"</span>
</pre></div>
<p>Then you can use <code>laravel</code> command to create a new project:</p>
<div class="highlight"><pre><span></span>$ laravel new myproject
</pre></div>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Basic Usage for Docker]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2017/11/docker-basic.html"/>
<published>2017-11-06T16:12:00+08:00</published>
<updated>2020-02-01T10:09:36+08:00</updated>
<id>http://terryoy.github.io/2017/11/docker-basic.html</id>
<category scheme="http://terryoy.github.io/tag/#linux" term="linux" label="linux" />
<category scheme="http://terryoy.github.io/tag/#docker" term="docker" label="docker" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <p>Just to keep some notes when started to use docker for my development projects.</p>
<h3 id="toc_0">0. Get Started</h3>
<p>For my mac, download the .dmg file from official web site. Then it will run a program with a task icon in the top bar.</p>
<p>After the program has been initialized, you can open a terminal and try a few commands:</p>
<div class="highlight"><pre><span></span><span class="c1"># check versions</span>
$ docker --version
$ docker-compose --version
$ docker-machine --version
<span class="c1"># Current images</span>
$ docker images
<span class="c1"># Running instances</span>
$ docker ps
</pre></div>
<h3 id="toc_1">1. First Instance</h3>
<p>The docker official Hello World image is small enough, which you can try as your first instance.</p>
<div class="highlight"><pre><span></span>$ docker run hello-world
</pre></div>
<p>The image does not exist locally currently, but docker will continue to try downloading it and then run it.</p>
<p>Then, you wil see the image locally.</p>
<div class="highlight"><pre><span></span>$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 725dcfab7d63 <span class="m">2</span> days ago <span class="m">1</span>.84kB
</pre></div>
<p>However, the container for this image is not visible in the list because <strong>the process has existed</strong>. You need to use a <code>-a</code> parameter to see it:</p>
<div class="highlight"><pre><span></span>$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c32eac048fda hello-world <span class="s2">"/hello"</span> <span class="m">5</span> minutes ago Exited <span class="o">(</span><span class="m">0</span><span class="o">)</span> <span class="m">5</span> minutes ago cranky_shaw
</pre></div>
<h3 id="toc_2">2. Server Instance</h3>
<p>The Hello World container doesn't do anything. If you want to try something interesting, try the <a href="https://docs.docker.com/docker-for-mac/#explore-the-application-and-run-examples">nginx image</a> instead.</p>
<div class="highlight"><pre><span></span>$ docker run -d -p <span class="m">8001</span>:80 --name webserver1 nginx
</pre></div>
<p>I choose a different port for the server, just to show how the port mapping is handled. When you check the instance with <code>docker ps</code>, you can see the image name, instance name, and the port mapping and get the meaning. When the container is up, you can access <code>http://localhost:8001/</code> to see the nginx home page.</p>
<div class="highlight"><pre><span></span>$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6f6ba1d3f285 nginx <span class="s2">"nginx -g 'daemon ..."</span> About a minute ago Up About a minute <span class="m">0</span>.0.0.0:8001->80/tcp webserver1
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 40960efd7b8f <span class="m">38</span> hours ago 108MB
hello-world latest 725dcfab7d63 <span class="m">2</span> days ago <span class="m">1</span>.84kB
</pre></div>
<p>A good point is that you can see how much disk usage every image uses. Now you can stop the service, or remove the unused resources by commands.</p>
<div class="highlight"><pre><span></span><span class="c1"># container life cycle methods</span>
$ docker stop webserver1
$ docker start webserver1
$ docker restart webserver1
<span class="c1"># remove a container</span>
$ docker rm webserver1
<span class="c1"># remove an image</span>
$ docker rmi hello-world
</pre></div>
<p>For server instance like Ubuntu, you need an interactive shell to work with it, so the command will be a little bit different:</p>
<pre><code># start a new container named 'ubuntu'
$ docker run --name ubuntu -ti ubuntu-core
# run an existing container
$ docker container start -i ubuntu
# attach console to a server if it has started without interactive environment
$ docker container start ubuntu
$ docker attach ubuntu
# If you want to detach from a server without stopping it
# use `ctrl-p ctrl-q` key sequence</code></pre>
<p>You may wonder the file size of each containers, you can checkt it by <code>docker ps -s</code>. You can see a ubuntu core only uses very small space with the minimal setup.</p>
<div class="highlight"><pre><span></span>$ docker ps -s
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE
070a6e845653 ubuntu <span class="s2">"/bin/bash"</span> About an hour ago Up About an hour ubuntu <span class="m">96</span>.7MB <span class="o">(</span>virtual 219MB<span class="o">)</span>
0200f61f5d65 nginx <span class="s2">"nginx -g 'daemon ..."</span> <span class="m">2</span> hours ago Up <span class="m">2</span> hours <span class="m">0</span>.0.0.0:5000->80/tcp webserver 2B <span class="o">(</span>virtual 108MB<span class="o">)</span>
</pre></div>
<h3 id="toc_3">3. Other Settings</h3>
<p>There are some Docker preferences also mentioned in the Get Started guide, which I should make some notes here:</p>
<ul>
<li><strong>Disk Image Location</strong>. on Mac, it is stored in a file called “Docker.qcow2” somewhere in ~/Library, and all the containers are store within this image. You can move it somewhere else.</li>
<li><strong>Experimental features</strong>. It is not recommended for production environment, then I wonder why it is turned on by default on Mac.</li>
<li>*<em>Registry, Configuration, and Certificates for the Daemon *</em>, use it when you needed.</li>
</ul>
<h4 id="toc_4">3.1 Download Images by Tags</h4>
<div class="highlight"><pre><span></span><span class="c1"># Download images/repos from registry</span>
$ docker pull <image>:<tag>
<span class="c1"># Example of getting a core ubuntu system</span>
$ docker pull ubuntu:xenial
$ docker run --name ubuntu -ti ubuntu
</pre></div>
<h3 id="toc_5">4. Docker for Mac vs Docker Toolbox</h3>
<p>Docker Toolbox is also installed by the .dmg installation. The programs include <code>docker-compose</code> and <code>docker-machine</code>.</p>
<ul>
<li>Docker for Mac is a Mac native application, you get only one VM, and it is managed by Docker for Mac. The VM is used with a lightweight solution called HyperKit.</li>
<li>Using Dokcker Toolbox, you can set up one or more VM and manage them.</li>
</ul>
<h3 id="toc_6">5. Docker Architecture</h3>
<p>The Docker architecture can split into 3 parts:</p>
<ul>
<li>Docket Client, the <code>docker</code> cli tools for user to interact with docker daemon with Docker API.</li>
<li>Docker Host, the service daemon <code>dockerd</code> listen for Docker API request and perform all kinds of management tasks about images, containers, networks, and volumns.</li>
<li>Docker Registry, a cloud service which stores Docker images, such as Docker Hub and Docker Cloud(both are public registries).</li>
</ul>
<h4 id="toc_7">5.1 Docker Objects</h4>
<ul>
<li>Image, a read-only template with instructions for creating Docker container.</li>
<li>Container, an instance of an image, with network, file system, etc. attached. You can create, delete, stop, resume containers.</li>
<li>Service, allow you to scale containers across Docker daemons.</li>
</ul>
<h4 id="toc_8">5.2 The Underlying technology</h4>
<ul>
<li>Namespaces. When you run a container, Docker create a set of namespaces for the container, which provide a layer of isolation. The namespaces includes:
<ul>
<li><code>pid</code> for process</li>
<li><code>net</code> for network interfaces</li>
<li><code>ipc</code> for interprocess communication</li>
<li><code>mnt</code> for file system</li>
<li><code>uts</code> for kernel and version identifiers (Unix Timeshare System)</li>
</ul></li>
<li>Control Groups. A <code>cgroup</code> limits an application to a specific set of resources, and allow Docker Engine to share hardware resources to containers with optionally limits and constraints.</li>
<li>Container Format. A combination of namespaces, control groups, and UnionFS, packed into a Wrapper. The default format is <code>libcontainer</code>.</li>
</ul>
<p>Refs:
<a href="https://docs.docker.com/engine/docker-overview/#docker-architecture">Docker Architecture</a>
<a href="https://store.docker.com/">Docker Store</a> is a market where you can distribute your images.</p>
<h3 id="toc_9">6. Developing Apps with Docker</h3>
<p>It's easy to setup Docker to deploy with your app. All you need to do is to add a <code>Dockerfile</code> in your source folder and then build the image. The official example demonstrate how a small flask app is built with Docker.</p>
<h4 id="toc_10">6.1 First time image</h4>
<p>I summarize the steps as below:</p>
<ul>
<li>Go to docker <a href="https://hub.docker.com/_/python/">hub</a> to find a target python image. It already has all kinds of Dockerfile template for you to copy.</li>
<li>Create a local copy of the Docker file. Make sure you understand the template and knows what to modify according to your app.</li>
<li>Write a flask <code>app.py</code> and a <code>requirements.txt</code> as usual.</li>
<li>Build the docker image and then run with it.</li>
</ul>
<div class="highlight"><pre><span></span><span class="c1"># prepare the source files(...skipped here)</span>
$ ls
Dockerfile app.py requirements.txt
<span class="c1"># build the image</span>
$ docker build -t slim-flask .
<span class="c1"># create and run the container</span>
$ docker run -p <span class="m">4000</span>:80 slim-flask
* Running on http://0.0.0.0:80/ <span class="o">(</span>Press CTRL+C to quit<span class="o">)</span>
</pre></div>
<p>The result will be:</p>
<ul>
<li>Only a Dockerfile is added to your source, and others are still remain</li>
<li>A Python docker image is downloaded, which takes the size of 156MB or 691MB depends on if you choose the “slim” version.</li>
<li>A flask image for your app is genenrated, which contains the content from the original python image, the pip installed packages from requirements, and your source files. So the size is slightly bigger than the python image.</li>
</ul>
<div class="highlight"><pre><span></span>$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
slim-flask latest 3032f935f40c <span class="m">10</span> seconds ago 166MB
python slim a79297999298 <span class="m">45</span> hours ago 156MB
</pre></div>
<h4 id="toc_11">6.2 Create image from a container</h4>
<p>However, sometimes you want to make configurations inside a container and want to save it as an image. You can do that:</p>
<div class="highlight"><pre><span></span>$ docker container commit <span class="o">[</span>options<span class="o">]</span> CONTAINER <span class="o">[</span>repository:<span class="o">[</span>TAG<span class="o">]]</span>
<span class="c1"># example</span>
$ docker container commit ubuntu ubuntu-image
</pre></div>
<h4 id="toc_12">6.3 Publish docker image</h4>
<p>Use it when it is needed.</p>
<div class="highlight"><pre><span></span>$ docker login <span class="c1"># Log in this CLI session using your Docker credentials</span>
$ docker tag <image> username/repository:tag <span class="c1"># Tag <image> for upload to registry</span>
$ docker push username/repository:tag <span class="c1"># Upload tagged image to registry</span>
$ docker run username/repository:tag <span class="c1"># Run image from a registry</span>
</pre></div>
<h3 id="toc_13">7. Docker mirrors</h3>
<ul>
<li>Docker(Official), <code>--registry-mirror=https://registry.docker-cn.com</code></li>
<li>Netease, <a href="http://hub-mirror.c.163.com">hub-mirror.c.163.com</a></li>
<li>USTC, <a href="https://docker.mirrors.ustc.edu.cn">docker.mirrors.ustc.edu.cn</a></li>
<li>Daocloud & Alicloud, need registration, and Alicloud needs an dev platform account.</li>
</ul>
<p><a href="https://ieevee.com/tech/2016/09/28/docker-mirror.html">source</a></p>
]]>
</content>
</entry><entry>
<title type="html"><![CDATA[Python Function Decorators and The Use in Django]]></title>
<author><name>terryoy</name></author>
<link href="http://terryoy.github.io/2017/03/python-decorators-and-use-in-django.html"/>
<published>2017-03-26T16:26:00+08:00</published>
<updated>2020-02-01T10:09:37+08:00</updated>
<id>http://terryoy.github.io/2017/03/python-decorators-and-use-in-django.html</id>
<category scheme="http://terryoy.github.io/tag/#python" term="python" label="python" />
<content type="html" xml:base="http://terryoy.github.io/" xml:lang="en">
<![CDATA[ <h3 id="toc_0">1. Basic of functions</h3>
<ul>
<li>Functions can be assign</li>
<li>Functions can be defined inside a function</li>
<li>Functions can be passed as a parameter and return as a returning value</li>
<li>Inner functions have access to the enclosing scope</li>
</ul>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'World'</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'Hello, </span><span class="si">{0}</span><span class="s1">!'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="p">)))</span>
<span class="c1"># assign</span>
<span class="n">bar</span> <span class="o">=</span> <span class="n">foo</span>
<span class="n">bar</span><span class="p">()</span>
<span class="c1"># => Hello, world!</span>
<span class="c1"># Use in parameter and return as result</span>
<span class="k">def</span> <span class="nf">greetings</span><span class="p">(</span><span class="n">call</span><span class="p">):</span>
<span class="n">welcome</span> <span class="o">=</span> <span class="s1">'Welcome back!'</span> <span class="c1"># the enclosing scope to "greeting_to"</span>
<span class="k">def</span> <span class="nf">greeting_to</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="n">call</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">welcome</span><span class="p">)</span>
<span class="k">return</span> <span class="n">greeting_to</span>
<span class="n">greet</span> <span class="o">=</span> <span class="n">greetings</span><span class="p">(</span><span class="n">bar</span><span class="p">)</span> <span class="c1"># set bar as a greeting function</span>
<span class="n">greet</span><span class="p">(</span><span class="s1">'Terry'</span><span class="p">)</span> <span class="c1"># use the return function to generate greetings</span>
<span class="c1"># => Hello, Terry!</span>
<span class="c1"># => Welcome, back!</span>
</pre></div>
<h3 id="toc_1">2. Decorators</h3>
<p>A <strong>Function Decorator</strong> is a wrapper to an existing function, in which you can do some pre-process to the parameter or post-process to the returning value of the existing funciton.</p>
<p>The function decorator in Python must follows the below rules:</p>
<ul>
<li>It is a function that accept a function parameter(like saying <em>“a decorator to which function”</em>)</li>
<li>The decorator function must define and return a function as a result, so that the client gets something act similar to the existing function(act just like a function wrapper). </li>
<li>Do the customizing things inside the wrapper function, and call the existing function eventually</li>
</ul>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">greeting_decorator</span><span class="p">(</span><span class="n">call</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="n">call</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Isn't it powerful?"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">wrapper</span>
<span class="c1"># The decorator syntax</span>
<span class="nd">@greeting_decorator</span>
<span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Hello, </span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
<span class="n">greet</span><span class="p">(</span><span class="s1">'Terry'</span><span class="p">)</span> <span class="c1"># decorated function though the function name is the same as defined</span>
<span class="c1"># => Hello, Terry </span>
<span class="c1"># => Isn't it powerful?</span>
</pre></div>
<p>Decorators can be chained, and can also accept extra parameters when defining the customization to the function. However, decorators that accept parameters need to add another wrapper to the simple decorator.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">room</span><span class="p">(</span><span class="n">room_name</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">decorator_wrapper</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Enter room: </span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">room_name</span><span class="p">))</span>
<span class="n">func</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="k">return</span> <span class="n">wrapper</span>
<span class="k">return</span> <span class="n">decorator_wrapper</span>
<span class="k">def</span> <span class="nf">leave_on_greet</span><span class="p">(</span><span class="n">greet_func</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">greeting_wrapper</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="n">greet_func</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Thanks, I'm leaving"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">greeting_wrapper</span>
<span class="nd">@room</span><span class="p">(</span><span class="s1">'Matrix'</span><span class="p">)</span>
<span class="nd">@leave_on_greet</span>
<span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Hello, </span><span class="si">{0}</span><span class="s2">"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
<span class="n">greet</span><span class="p">(</span><span class="s1">'Terry'</span><span class="p">)</span>
<span class="c1"># => Enter room: Matrix</span>
<span class="c1"># => Hello, Terry</span>
<span class="c1"># => Thanks, I'm leaving</span>
</pre></div>
<h3 id="toc_2">3. Example: using decorator in Django views</h3>
<p>It is very common that you want to write decorators for the request in views.py. For example, Django itself provides <a href="https://docs.djangoproject.com/en/1.10/topics/http/decorators/">a list of decorators</a> that you can use in certain scenarios, such as restricting HTTP methods, or cache controls. There are also other examples that could be consider: logging requests or checking auth tokens.</p>
<p>Here I write a very simple example that logs requests which a specified module name. We will have to use a new feature here that passes arguments between functions, because Django view methods can accept arguments defined in URL patterns.</p>
<div class="highlight"><pre><span></span><span class="c1"># a request log decorator which you can define the module</span>
<span class="k">def</span> <span class="nf">log_request</span><span class="p">(</span><span class="n">module</span><span class="o">=</span><span class="s2">""</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">decorator_wrapper</span><span class="p">(</span><span class="n">view_func</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">func_wrapper</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">'[</span><span class="si">{0}</span><span class="s1">] </span><span class="si">{1}</span><span class="s1"> </span><span class="si">{2}</span><span class="s1"> </span><span class="si">{3}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">get_host</span><span class="p">(),</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">get_full_path</span><span class="p">()))</span>
<span class="k">return</span> <span class="n">view_func</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">func_wrapper</span>
<span class="k">return</span> <span class="n">decorator_wrapper</span>
<span class="c1"># use in views.py</span>
<span class="nd">@log_request</span><span class="p">(</span><span class="n">module</span><span class="o">=</span><span class="s2">"Book"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">book_detail</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">book_id</span><span class="p">):</span>
<span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s1">'Book info: </span><span class="si">{0}</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">book_id</span><span class="p">))</span>