续CentOS 7 Docker基本特性入门实践-1
构建Image
通过创建Dockerfile可以构建Image,Docker会从一个Dockerfile中读取一系列指令来构建Image。一个Dockerfile是一个文本文件,它包含了一组能够运行的命令行,这些命令行就组装成了一个Docker Image。 下面,我们看一下前面提到的名称为hello-world的Image是如何构建,可以在Github上看到该Image的代码,链接在这里:https://github.com/docker-library/hello-world。 hello-world一定对应一个Dockerfile,内容如下所示:
1 FROM scratch 2 COPY hello / 3 CMD ["/hello"]上面这3条命令,就对应着hello-world这个Image: 第一行,FROM命令:是从一个已知的基础Image来构建新的Image,这里scratch是一个显式指定的空Image; 第二行,COPY命令:是将指定的新文件或目录,拷贝到Container中指定的目录下面,这里讲hello这个可执行文件复制到Container中的根路径/下面; 第三行,CMD命令:是运行指定的命令行,包含指定的命令名称、参数列表 可见,上面的hello可执行文件是已经构编译好的文件,它是从一个C程序文件(Github链接:https://github.com/docker-library/hello-world/blob/master/hello.c)编译而来的,源码文件hello.c内容如下所示:
01 #include <sys/syscall.h> 02 03 #ifndef DOCKER_IMAGE 04 #define DOCKER_IMAGE "hello-world" 05 #endif 06 07 #ifndef DOCKER_GREETING 08 #define DOCKER_GREETING "Hello from Docker!" 09 #endif 10 11 const char message[] = 12 "\n" 13 DOCKER_GREETING "\n" 14 "This message shows that your installation appears to be working correctly.\n" 15 "\n" 16 "To generate this message, Docker took the following steps:\n" 17 " 1. The Docker client contacted the Docker daemon.\n" 18 " 2. The Docker daemon pulled the \"" DOCKER_IMAGE "\" image from the Docker Hub.\n" 19 " 3. The Docker daemon created a new container from that image which runs the\n" 20 " executable that produces the output you are currently reading.\n" 21 " 4. The Docker daemon streamed that output to the Docker client, which sent it\n" 22 " to your terminal.\n" 23 "\n" 24 "To try something more ambitious, you can run an Ubuntu container with:\n" 25 " $ docker run -it ubuntu bash\n" 26 "\n" 27 "Share images, automate workflows, and more with a free Docker ID:\n" 28 " https://cloud.docker.com/\n" 29 "\n" 30 "For more examples and ideas, visit:\n" 31 " https://docs.docker.com/engine/userguide/\n" 32 "\n"; 33 34 void _start() { 35 //write(1, message, sizeof(message) - 1); 36 syscall(SYS_write, 1, message, sizeof(message) - 1); 37 38 //_exit(0); 39 syscall(SYS_exit, 0); 40 }编译生成可执行文件hello,然后可以使用Docker的build命令来构建生成Image:
1 docker build -t hello-world现在,hello-world是如何构建Image的就已经非常清楚了。下面,我们通过参考官网的用户指南,编写一个Dockerfile来制作一个Image,了解如何实现自己的应用:
编写Dockerfile首先,创建一个单独的目录来存放我们将要构建的Dockerfile文件:
1 mkdir mydockerbuild 2 cd mydockerbuild 3 vi Dockerfile在Dockerfile中输入如下内容:
1 FROM docker/whalesay:latest 2 RUN apt-get -y update && apt-get install -y fortunes 3 CMD /usr/games/fortune -a | cowsay上面FROM命令表示,Docker基于该docker/whalesay:latest来构建新的Image,这个Image在Docker Hub上,链接在这里:https://hub.docker.com/r/docker/whalesay/,对应的源码可以看Github:https://github.com/docker/whalesay。RUN命令行表示安装fortunes程序包,最后的CMD命令指示将运行/usr/games/fortune命令。
构建Image保存上述3行命令到文件中,在当前mydockerbuild目录中执行构建Image的命令:
1 docker build -t docker-whale .构建过程,输出信息如下:
01 Sending build context to Docker daemon 2.048 kB 02 Step 1/3 : FROM docker/whalesay:latest 03 ---> 6b362a9f73eb 04 Step 2/3 : RUN apt-get -y update && apt-get install -y fortunes 05 ---> Running in bfddc2134d23 06 Ign http://archive.ubuntu.com trusty InRelease 07 Get:1 http://archive.ubuntu.com trusty-updates InRelease [65.9 kB] 08 Get:2 http://archive.ubuntu.com trusty-security InRelease [65.9 kB] 09 Hit http://archive.ubuntu.com trusty Release.gpg 10 Get:3 http://archive.ubuntu.com trusty-updates/main Sources [485 kB] 11 Get:4 http://archive.ubuntu.com trusty-updates/restricted Sources [5957 B] 12 Get:5 http://archive.ubuntu.com trusty-updates/universe Sources [220 kB] 13 Get:6 http://archive.ubuntu.com trusty-updates/main amd64 Packages [1197 kB] 14 Get:7 http://archive.ubuntu.com trusty-updates/restricted amd64 Packages [20.4 kB] 15 Get:8 http://archive.ubuntu.com trusty-updates/universe amd64 Packages [516 kB] 16 Get:9 http://archive.ubuntu.com trusty-security/main Sources [160 kB] 17 Get:10 http://archive.ubuntu.com trusty-security/restricted Sources [4667 B] 18 Get:11 http://archive.ubuntu.com trusty-security/universe Sources [59.4 kB] 19 Get:12 http://archive.ubuntu.com trusty-security/main amd64 Packages [730 kB] 20 Get:13 http://archive.ubuntu.com trusty-security/restricted amd64 Packages [17.0 kB] 21 Get:14 http://archive.ubuntu.com trusty-security/universe amd64 Packages [199 kB] 22 Hit http://archive.ubuntu.com trusty Release 23 Hit http://archive.ubuntu.com trusty/main Sources 24 Hit http://archive.ubuntu.com trusty/restricted Sources 25 Hit http://archive.ubuntu.com trusty/universe Sources 26 Hit http://archive.ubuntu.com trusty/main amd64 Packages 27 Hit http://archive.ubuntu.com trusty/restricted amd64 Packages 28 Hit http://archive.ubuntu.com trusty/universe amd64 Packages 29 Fetched 3745 kB in 55s (67.1 kB/s) 30 Reading package lists... 31 Reading package lists... 32 Building dependency tree... 33 Reading state information... 34 The following extra packages will be installed: 35 fortune-mod fortunes-min librecode0 36 Suggested packages: 37 x11-utils bsdmainutils 38 The following NEW packages will be installed: 39 fortune-mod fortunes fortunes-min librecode0 40 0 upgraded, 4 newly installed, 0 to remove and 92 not upgraded. 41 Need to get 1961 kB of archives. 42 After this operation, 4817 kB of additional disk space will be used. 43 Get:1 http://archive.ubuntu.com/ubuntu/ trusty/main librecode0 amd64 3.6-21 [771 kB] 44 Get:2 http://archive.ubuntu.com/ubuntu/ trusty/universe fortune-mod amd64 1:1.99.1-7 [39.5 kB] 45 Get:3 http://archive.ubuntu.com/ubuntu/ trusty/universe fortunes-min all 1:1.99.1-7 [61.8 kB] 46 Get:4 http://archive.ubuntu.com/ubuntu/ trusty/universe fortunes all 1:1.99.1-7 [1089 kB] 47 debconf: unable to initialize frontend: Dialog 48 debconf: (TERM is not set, so the dialog frontend is not usable.) 49 debconf: falling back to frontend: Readline 50 debconf: unable to initialize frontend: Readline 51 debconf: (This frontend requires a controlling tty.) 52 debconf: falling back to frontend: Teletype 53 dpkg-preconfigure: unable to re-open stdin: 54 Fetched 1961 kB in 5s (340 kB/s) 55 Selecting previously unselected package librecode0:amd64. 56 (Reading database ... 13116 files and directories currently installed.) 57 Preparing to unpack .../librecode0_3.6-21_amd64.deb ... 58 Unpacking librecode0:amd64 (3.6-21) ... 59 Selecting previously unselected package fortune-mod. 60 Preparing to unpack .../fortune-mod_1:1.99.1-7_amd64.deb ... 61 Unpacking fortune-mod (1:1.99.1-7) ... 62 Selecting previously unselected package fortunes-min. 63 Preparing to unpack .../fortunes-min_1:1.99.1-7_all.deb ... 64 Unpacking fortunes-min (1:1.99.1-7) ... 65 Selecting previously unselected package fortunes. 66 Preparing to unpack .../fortunes_1:1.99.1-7_all.deb ... 67 Unpacking fortunes (1:1.99.1-7) ... 68 Setting up librecode0:amd64 (3.6-21) ... 69 Setting up fortune-mod (1:1.99.1-7) ... 70 Setting up fortunes-min (1:1.99.1-7) ... 71 Setting up fortunes (1:1.99.1-7) ... 72 Processing triggers for libc-bin (2.19-0ubuntu6.6) ... 73 ---> 98403143b081 74 Removing intermediate container bfddc2134d23 75 Step 3/3 : CMD /usr/games/fortune -a | cowsay 76 ---> Running in 8831a7231adc 77 ---> 08d234c4ee26 78 Removing intermediate container 8831a7231adc 79 Successfully built 08d234c4ee26或者,可以通过-f选项,直接指定Dockerfile文件的绝对路径,构建命令如下所示:
1 docker build -f ~/mydockerbuild/Dockerfile -t docker-whale .这样我们自己的Image就构建好了,名称为docker-whale。下面,看下构建我们这个Image的基本流程流程:
Docker检查确保当前Dockerfile中是否有需要build的内容 Docker检查是否存在whalesay这个Image Docker会启动一个临时的容器6b362a9f73eb,来运行whalesay这个image。在这个临时的Container中,Docker会执行RUN这行命令,安装fortune程序包 一个新的中间container被创建8831a7231adc,在Dockerfile中增加了一个CMD层(Layer),对应一个Container,然后中间container8831a7231adc被删除我们在构建一个Image时,会自动下载依赖的Docker Image,其实也可以预先下载对应的Image,使用类似下面的命令:
1 docker pull mysql:5.5这样就可以下载MySQL 5.5的Image到本地。
查看构建的Image查看当前image列表,其中包含我们刚刚构建好的Image,执行docker images命令,结果如下所示:
1 REPOSITORY TAG IMAGE ID CREATED SIZE 2 docker-whale latest 08d234c4ee26 9 minutes ago 256 MB 3 ubuntu latest f49eec89601e 5 weeks ago 129 MB 4 hello-world latest 48b5124b2768 6 weeks ago 1.84 kB 5 docker/whalesay latest 6b362a9f73eb 21 months ago 247 MB第一个docker-whale,就是我们自己创建的。
启动Docker Container接着,基于我们已经构建好的Image,在Docker Container中运行这个应用,执行命令:
1 docker run docker-whale运行结果,如下所示:
01 ______________________________ 02 / IBM: \ 03 | | 04 | I've Been Moved | 05 | | 06 | Idiots Become Managers | 07 | | 08 | Idiots Buy More | 09 | | 10 | Impossible to Buy Machine | 11 | | 12 | Incredibly Big Machine | 13 | | 14 | Industry's Biggest Mistake | 15 | | 16 | International Brotherhood of | 17 | Mercenaries | 18 | | 19 | It Boggles the Mind | 20 | | 21 | It's Better Manually | 22 | | 23 \ Itty-Bitty Machines / 24 ------------------------------ 25 \ 26 \ 27 \ 28 ## . 29 ## ## ## == 30 ## ## ## ## === 31 /""""""""""""""""___/ === 32 ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~ 33 \______ o __/ 34 \ \ __/ 35 \____\______/另外,我们可以进入到Docker Hub:https://hub.docker.com,创建一个自己的账号,然后创建自己的Image,当然也可以找到各种免费共享的Image,可以基于这些Image来构建自己的Image。Docker Hub页面,如下所示: 下面是一个例子,可以在启动Docker Container时,通过命令行直接向Container内部应用传递参数值,命令行如下所示:
1 docker run docker/whalesay cowsay boo 2 docker run docker/whalesay cowsay boo-boo可以看到,输出的内容根据启动Container传递的参数值而变化。
查看Docker Container查看当前主机上所有状态的Docker Container,可以执行如下命令(下面的命令都是等价的):
1 docker ps -a 2 docker container ps -a 3 docker container ls -a示例结果,如下所示:
1 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2 5ab157767bbd training/postgres "su postgres -c '/..." 6 seconds ago Up 5 seconds 5432/tcp pgdb 3 da91889d6313 training/postgres "su postgres -c '/..." 49 seconds ago Up 2 seconds 5432/tcp webappdb 4 5d86616e9a1d docker-whale "/bin/sh -c '/usr/..." 24 minutes ago Exited (0) 7 seconds ago elastic_mcnulty 5 abec6410bcac docker/whalesay "cowsay boo" 27 minutes ago Exited (0) 27 minutes ago upbeat_edison 6 72d0b2bb5d6a training/postgres "su postgres -c '/..." 4 hours ago Up 4 hours 5432/tcp db 7 fc9b0bb6ae8e ubuntu "/bin/bash" 4 hours ago Up 4 hours networktest 8 fc9b0bb6ae8e ubuntu "/bin/bash" 7 days ago Exited (255) 3 days ago networktest查看当前运行中的Container,可以执行如下命令查看(下面的命令都是等价的):
1 docker ps 2 docker container ps 3 docker container lsDocker网络
Docker支持Container之间通过网络互连,提供了两种网络Driver,分别为Bridge和Overlay,我们也可以实现自己的网络Driver插件来管理我们的Docker Container网络。目前,有很多Docker网络的解决方案,如Flannel、Weave、Pipework、libnetwork等,感兴趣可以深入研究一下。 在安装Docker Engine之后,会包含三个默认的网络,可以通过如下命令查看当前所有的网络:
1 docker network ls结果如下所示:
1 NETWORK ID NAME DRIVER SCOPE 2 b92d9ca4d992 bridge bridge local 3 6d33880bf521 host host local 4 a200b158f39c none null local名称为host的网络,表示宿主机的网络,如果启动Docker Container指定该网络,则Container与宿主机使用相同的Network Namespace,也就是启动的Container的网络会使用宿主机的网卡、IP、端口。 在启动Docker Container时,如果我们没有显式指定网络名称,Docker会使用默认的bridge网络。这种网络模式下,Docker会为Container创建一个独立于宿主机的Network Namespace,并使用独立的IP段,Container连接到一个虚拟网桥上,默认是docker0网桥。虚拟网桥与交换机的工作方式类似,启动的Docker Container连接到虚拟网桥上,这就构成了一个二层网络。 为了更加直观说明,我们参考了网上的一个Docker网络的结构图,如下图所示: 下面,通过Docker网络功能,看如何将Container网络连接起来。
创建Docker网络创建一个Docker网络,名称为my-bridge-network,执行如下命令:
1 docker network create -d bridge my-bridge-network创建的结果,输出了新建Docker网络的ID,如下所示:
1 fc19452525e5d2f5f1fc109656f0385bf2f268b47788353c3d9ee672da31b33a上面fc19452525e5d2f5f1fc109656f0385bf2f268b47788353c3d9ee672da31b33a就是新创建网络my-bridge-network的ID,可以通过如下命令查看:
1 docker network ls当前主机上存在的所有Docker网络信息,如下所示:
1 NETWORK ID NAME DRIVER SCOPE 2 b92d9ca4d992 bridge bridge local 3 6d33880bf521 host host local 4 fc19452525e5 my-bridge-network bridge local 5 a200b158f39c none null local 查看一个Docker网络查看一个Docker网络的详细信息,查看默认的bridge网络,可以执行如下命令:
1 docker network inspect bridge执行结果,如下所示:
01 [ 02 { 03 "Name": "bridge", 04 "Id": "2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6", 05 "Created": "2017-03-05T21:46:12.413438219+08:00", 06 "Scope": "local", 07 "Driver": "bridge", 08 "EnableIPv6": false, 09 "IPAM": { 10 "Driver": "default", 11 "Options": null, 12 "Config": [ 13 { 14 "Subnet": "172.17.0.0/16", 15 "Gateway": "172.17.0.1" 16 } 17 ] 18 }, 19 "Internal": false, 20 "Attachable": false, 21 "Containers": { 22 "5ab157767bbd991401c351cfb452d663f5cd93dd1edc56767372095a5c2e7f73": { 23 "Name": "pgdb", 24 "EndpointID": "e0368c3219bcafea7c2839b7ede628fa67ad0a5350d150fdf55a4aa88c01c480", 25 "MacAddress": "02:42:ac:11:00:02", 26 "IPv4Address": "172.17.0.2/16", 27 "IPv6Address": "" 28 }, 29 "da91889d63139019bbdcc6266704fb21e0a1800d0ae63b3448e65d1e17ef7368": { 30 "Name": "webappdb", 31 "EndpointID": "422ab05dd2cbb55266964b31f0dd9292688f1459e3a687662d1b119875d4ce44", 32 "MacAddress": "02:42:ac:11:00:03", 33 "IPv4Address": "172.17.0.3/16", 34 "IPv6Address": "" 35 } 36 }, 37 "Options": { 38 "com.docker.network.bridge.default_bridge": "true", 39 "com.docker.network.bridge.enable_icc": "true", 40 "com.docker.network.bridge.enable_ip_masquerade": "true", 41 "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", 42 "com.docker.network.bridge.name": "docker0", 43 "com.docker.network.driver.mtu": "1500" 44 }, 45 "Labels": {} 46 } 47 ]通过上面结果信息可以看到,当前bridge网络的ID为2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6,在该Docker网络内部运行中的Container有2个,分别为pgdb和webapp,他们在Container内部的IP地址分别为172.17.0.2和172.17.0.3,因为在同一个bridge网络中,所以共享相同的IP地址段。 或者,我们也可以格式化输出某个Container所在网络的设置,执行如下命令:
1 docker inspect --format='{{json .NetworkSettings.Networks}}' pgdb输出结果如下所示(结果格式化过):
01 { 02 "bridge": { 03 "IPAMConfig": null, 04 "Links": null, 05 "Aliases": null, 06 "NetworkID": "2872de41fddddc22420eecad253107e09a305f3512ade31d4172d3b80723d8b6", 07 "EndpointID": "e0368c3219bcafea7c2839b7ede628fa67ad0a5350d150fdf55a4aa88c01c480", 08 "Gateway": "172.17.0.1", 09 "IPAddress": "172.17.0.2", 10 "IPPrefixLen": 16, 11 "IPv6Gateway": "", 12 "GlobalIPv6Address": "", 13 "GlobalIPv6PrefixLen": 0, 14 "MacAddress": "02:42:ac:11:00:02" 15 } 16 }可见和上面的命令类似,能输出Docker网络bridge的基本信息。
转载至:http://shiyanjun.cn/archives/1608.html
hu_wenjie 认证博客专家 Kubernetes/容器 Linux/CentOS 系统架构 运维开发工程师,负责系统各层级的自动化监控开发、系统的自动化巡检开发、熟悉微服务项目的自动化部署、集群方案部署、熟练掌握故障分析定位等。