Docker 的镜像跟容器
一、docker 是什么
Docker容器是Docker进程+镜像文件(Docker 镜像中包含了运行环境和配置)
官方定义:Docker是以Docker容器为资源分割和调度的基本单位,封装整个软件运行时环境,为开发者和系统管理员设计的,用于构建、发布和运行分布式应用的平台。是一个跨平台,可移植并且简单易用的容器解决方案。
Docker是通过内核虚拟化技术(namespace及cgroups等)来提供容器的资源隔离与安全保障等,由于Docker通过操作系统层的虚拟化实现隔离,所以Docker容器在运行时,不需要类似虚拟机VM额外的操作系统开销,提高资源利用率。
1.1 namespace 隔离容器的运行环境
- 当用dockerrun启动一个容器时,Docker 将在后台为容器创建一个独立的命名空间。命名空间提供了最基础也是最直接的隔离,在容器中运行的进程不会被运行在本地主机上的进程和其他容器通过正常渠道发现和影响。
- 从网络架构的角度来看,所有的容器实际上是通过本地主机的网桥接口(Docker0)进行相互通信,就像物理机器通过物理交换机通信一样。
1.2 控制组资源控制的安全
控制组是Linux容器机制中的另外一个关键组件,它负责实现资源的审计和限制。当用docker run启动一个容器时,Docker将在后台为容器创建一个独立的控制组策略集合。
它提供了很多有用的特性;以及确保各个容器可以公平地分享主机的内存、CPU、磁盘等资源;当然,更重要的是,控制组确保了当发生在容器内的资源压力不会影响到本地主机系统和其他容器。
尽管控制组不负责隔离容器之间相互访问、处理数据和进程,但是它在防止拒绝服务攻击(DDoS)方面是必不可少的。尤其是在多用户的平台(比如公有或私有的PaaS)上,控制组十分重要。例如,当某些应用容器出现异常的时候,可以保证本地系统和其他容器正常运行而不受影响。
优点
- 持续部署与测试:消除线上线下的环境差异,保证应用生命周期的环境一致性和标准化。开发人员利用镜像实现标准开发环境的构建, 开发完成后通过通过封装着完整环境和应用的镜像进行迁移,由此,测试和运维人员可以直接部署软件镜像来进行测试和发布,大大简 化了持续集成,测试和发布的过程。
- 跨云平台支持:Docker带来的最大好处就是其适配性,越来越多的云平台支持Docker,同时也让应用多平台混合部署成为可能。
- 环境标准化和版本控制:基于Docker提供的环境一致性和标准化,你可以使用Git等工具对Docker镜像进行版本控制,相比基于代码的版本控制来说,你还能够对整个应用运行环境进行本本控制,一旦出现故障可以快速回滚。相比以前的虚拟机镜像,Docker压缩和备份的速度更快,镜像启动也像启动一个普通进程一样快。
- 高资源利用率和隔离:Docker容器没有管理程序的额外开销,与底层共享操作系统,性能更加优良,系统负载更低,在同等条件下可以运行更多的应用实 例,可以更充分的利用系统资源。同时,Docker拥有不错的资源隔离与限制能力,可以精确的对应用分配CPU、内存等资源,保证应用 间不会相互影响
- 容器跨平台性和镜像:Docker为容器设定了一整套标准化的配置方法,将应用及其依赖的运行环境打包成镜像,真正实现了“构建一次,到处运行”的理念, 大大提高了容器的跨平台性
- 应用镜像仓库:Docker官方构建了一个镜像仓库,
二、docker基本操作
->docker --version #查看版本
Docker version 17.09.0-ce, build afdb6d4复制代码
搜索一个image并且拉取下来
下载镜像的命令非常简单,使用docker pull命令即可。在docker的镜像网站上面,镜像都是按照"用户名/镜像名"的方式来存储的。
可以使用docker images查看拉取下来的镜像,其中IMAGE ID就是镜像id,删除镜像时可以使用这个IMAGE ID删除 docker rmi [IMAGE ID,REPOSITORY]
->docker search centos
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
centos The official build of CentOS. 3824 [OK]
...
->docker pull centos #拉取镜像
->docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest a7876479f1aa 4 years ago 128MB
->docker rmi a7876479f1aa #删除image复制代码
在docker容器中运行hello world,使用docker run创建一个容器,docker run之后就会产生一个容器并且保存起来,之后要运行就可以做直接运行容器而不用从新创建容器,这里的容器就是 container,docker的容器可以理解为在沙盒中运行的进程。这个沙盒包含了该进程运行所必须的资源,包括文件系统、系统类库、shell 环境等等。但这个沙盒默认是不会运行任何程序的。需要在沙盒中运行一个进程来启动某一个容器。这个进程是该容器的唯一进程,所以当该进程结束的时候,容器也会完全的停止。
可以通过 docker ps 查看正在运行的容器,当我们运行docker run centos echo "hello word"后看到输出 "hello word" 后再运行 docker ps 时没有任何容器输出出来,这是因为容器在运行完 echo "hello word" 后没有运行任何进程,所以容器就退出了。通过 docker ps -a 可以查看到所有的 container
->docker run centos echo "hello word" #通过 centos 镜像创建一个容器来输出 "hello word"
hello word
->docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e46ec634bbe1 centos "echo 'hello word'" 12 minutes ago Exited (0) 12 minutes ago复制代码
接下来就是给容器安装一个简单的程序。之前下载的是centos镜像,所以可以使用 yum 命令来安装程序。
备注:yum 命令执行完毕之后,容器就会停止,但对容器的改动不会丢失。但是从 image 重新 run 一个容器出来,之前安装的程序并不存在,因为所有的修改都是针对容器 (container) 的,并不针对 image,所以从 image run 出来的容器都是一个全新的
->docker run centos yum -y install net-tools
->docker ps -a #可以看到已经存在两个 container
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2f1bbd6c30e3 centos "yum install -y ne..." 1 minutes ago Exited (0) 1 minute ago competent
35129633c933 centos "echo hello word" 1 minutes ago Exited (0) 1 minute ago dazzling复制代码
现在容器是有了,需要的程序也安装好了,但就是只有一个容器,不能运行又有什么用,别急下面就来看看运行容器,但运行容器也有几种方法,一种就是在创建容器的时候并运行,之前说过,容器要保持运行就需要一个活动的进程,当容器内所有的进程都退出了,那么容器也就相应的停止了,所以要创建容器并保持运行容器的话很简单,用ping命令就可以了。
->docker run centos ping lozz.cc
PING lorencoll.coding.me (103.218.240.147) 56(84) bytes of data.
64 bytes from 103.218.240.147 (103.218.240.147): icmp_seq=1 ttl=37 time=16.0 ms
64 bytes from 103.218.240.147 (103.218.240.147): icmp_seq=2 ttl=37 time=16.4 ms
Ctrl+C
->docker ps #查看活动的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10c5c2754279 centos "ping lozz.cc" About a minute ago Up About a minute jolly复制代码
有启动就会有停止,停止可以用 docker stop container_id 命令来停止某个容器,好了现在开始讲第二种启动容器的方法,这种方法是在容器已经被创建的情况下使用的,我们知道每次 run 都是创建出一个新的容器,有的时候不需要创建,可以使用 docker start container_id 来启动一个容器,这时就需要注意了,启动后的容器没活动的进程容器依然是会退出的,因为容器是从镜像创建而来的,所以容器也是包含了创建这个容器的附加命令的,在 docker start 的时候又会从新执行一遍创建这个容器的附件命令,有点绕口是不是,敲一遍就知道了。
->docker ps #查看活动的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10c5c2754279 centos "ping lozz.cc" 23 minutes ago Up 23 minutes jolly
->docker ps -a #查看所有存在的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10c5c2754279 centos "ping lozz.cc" 21 minutes ago Up 21 minutes jolly
2f1bbd6c30e3 centos "yum install -y ne..." 36 minutes ago Exited (0) 3 minute ago competent
35129633c933 centos "echo hello word" About hour ago Exited (0) hour ago dazzling
# 尝试启动安装了 net-tools 的容器,
# -i 的意思是把信息输出到控制台中,没有这个参数执行后就直接返回一个CONTAINER ID
->docker start -i 2f1bbd6c30e3
Loaded plugins: fastestmirror, ovl
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.aliyun.com
* updates: mirrors.cn99.com
Package net-tools-2.0-0.22.20131004git.el7.x86_64 already installed and latest version
Nothing to do
->docker ps #查看活动的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10c5c2754279 centos "ping lozz.cc" 30 minutes ago Up 30 minutes jolly
->docker stop 10c5c2754279 #停止执行ping命令的容器
10c5c2754279
->docker start -i 10c5c2754279 #启动执行ping命令的容器
PING lorencoll.coding.me (103.72.144.62) 56(84) bytes of data.
64 bytes from 103.72.144.62 (103.72.144.62): icmp_seq=1 ttl=37 time=15.1 ms
64 bytes from 103.72.144.62 (103.72.144.62): icmp_seq=2 ttl=37 time=16.3 ms
64 bytes from 103.72.144.62 (103.72.144.62): icmp_seq=3 ttl=37 time=16.8 ms
Ctrl+C复制代码
从上面的提示就可以知道,这个 start 命令把之前创建命令 docker run centos yum -y install net-tools 中的 yum -y install net-tools 也执行了一遍,因为这个容器已经安装过了 net-tools ,所以 yum 才提示不需要安装,查看活动的容器中还是只有之前的容器在运行。那么现在有一个问题,我安装 net-tools 的那个容器不能用了吗,其实不然,这个容器之所以“不能用”只是因为创建的时候没有指定合适的命令,要用它也是可以的,我们把他从新打包成一个 image 也就是镜像,打包好了后再通过它生成容器就可以了,实际上这也符合 Docker 的应用隔离思想,把容器打包成镜像的命令很简单 docker commit container_id image_name,我的打包命令是 docker commit 2f1bbd6c30e3 lorenwe/centos_net_tools,这个命名是有规矩的,前面是 docker 的用户id,如果想要把这个镜像推送到 docker hub 这个名字就不能随便命名了,如果不推送到 docker hub 就无所谓了,但也不能太随便对不对。
->docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10c5c2754279 centos "ping lozz.cc" About an hour ago jolly
2f1bbd6c30e3 centos "yum install -y ne..." About an hour ago competent
35129633c933 centos "echo hello word" About an hour ago dazzling
->docker commit 2f1bbd6c30e3 lorenwe/centos_net_tools
sha256:35f8073cede14473601d9f138a9815bc9ab5c7d97f914ca2f5ce910bd78b5750
->docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
lorenwe/centos_net_tools latest 35f8073cede1 23 seconds ago 277MB
centos latest d123f4e55e12 2 weeks ago 197MB
d4w/nsenter latest 9e4f13a0901e 14 months ago 83.8kB复制代码
就这么简单,一个新的镜像(image)就创建好了,现在可以通过这个镜像来做些有趣的事情了,依然是 docker run 命令,只不过这次多增加一些参数,如 docker run -itd --name my_net_tools lorenwe/centos_net_tools /bin/bash
其中参数 itd 分别是表示 ‘标准输入给容器’,‘分配一个虚拟终端’,‘以守护进程方式运行(后台)’, --name 自然是指定创建后容器的名称了,/bin/bash 执行bash脚本,执行以上命令,就能创建一个后台运行的容器了。
->docker run -itd --name my_net_tools lorenwe/centos_net_tools /bin/bash
e1d843f7726f67d2635042695e2065b383736a341edd2e83753be9fabec03de0
->docker ps #查看活动的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e1d843f7726f lorenwe/centos_net_tools "/bin/bash" 7 seconds ago my_net_tools
10c5c2754279 centos "ping lozz.cc" Up 25 minutes jolly复制代码
嗯,运行了,然后呢,当然是可以进入容器中玩玩呀,使用 docker attach container_id 进入Docker容器
->docker attach e1d843f7726f
[root@e1d843f7726f /]# ip addr
bash: ip: command not found
[root@e1d843f7726f /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.3 netmask 255.255.0.0 broadcast 0.0.0.0
ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet)
RX packets 40 bytes 1900 (1.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@e1d843f7726f /]#复制代码
这个因为这个容器是基于 centos 来的,而 docker 的基础 centos 镜像都是精简版的,故很多命令没有,比如这个 ip addr ,这也是之前选择安装 net-tools 的原因,因为安装了这个就可以使用 ifconfig 来查看网卡配置。至此,是不是对 docker 有了一个基本的了解了呢,是不是突然来了一个灵感,比如想要搭建一个 Nginx 静态服务器,步骤就是 pull 一个基础镜像下来,通过这个基础镜像 run 出一个容器后再容器内安装上 Nginx 之后再从新打包成一个新的镜像就可以了。实际上使用 docke 构建镜像不会那样去做,步骤繁琐不说,还不是很灵活,毕竟之前构建的 lorenwe/centos_net_tools 镜像也有277MB呢!分发起来不太方便,于是 Dockerfile 出现了,其作用就是通过特定的格式把一个镜像描述出来,通过 docker 来构建出这个镜像,描述的流程其实和之前的手动构建的流程差不多,通过同一个 Dockerfile 可以构建出一模一样的环境,这也是 docke 常用于工作中统一系统运行环境的原因。
四、把 docker 推送到 docker hub
推送镜像的命令很简单,只需要 docker push image_name 就可以了,在把镜像推送到 docker hub 之前还是有一些准备工作要做的,需要先去 docker hub 注册一个账号,之后再在 docker 中登入这个账号就可以推送镜像了。
->docker login #登入到 docker hub
Login with your Docker ID to push and pull images from Docker Hub.
If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username (lorenwe): lorenwe
Password:
Login Succeeded
# 现在就可推送镜像到 docker hub
->docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
lorenwe/centos_net_tools latest 35f8073cede1 About an hour ago 277MB
centos latest d123f4e55e12 2 weeks ago 197MB
d4w/nsenter latest 9e4f13a0901e 14 months ago 83.8kB
->docker push lorenwe/centos_net_tools
The push refers to a repository [docker.io/lorenwe/centos_net_tools]
d0ba94ecc37e: Pushed
cf516324493c: Mounted from library/centos
latest: digest: sha256:276814315437cf5d416ed4b5713fe10c914beaea96bcf583b786a6778c80830f size: 741复制代码
由于墙和 docker hub 的服务器离天朝远的原因推送会很慢,成功后就能在 docker hub 的个人中心看到自己推送的镜像了,以后想要在使用这个镜像就可以直接 docker pull 就行了,也可以把镜像推送到国内的容器镜像服务平台,比如我用的是阿里云的容器Hub,可能是因为速度快吧所以用着舒服了,唯一不好的就是那又臭又长的镜像名称有点难受。
五、结语
docker 基础到这一步已经是介绍的差不多了,写这篇文章的目的就是用通俗易懂的语言及示例来讲明 docker 镜像与容器之间的关系,限于篇幅 docker 还有很多功能没有介绍,日后有时间再来做后续的文章,例如 Dockerfile,docker 卷的共享和网络通信等等都是一些特别有意思的功能,模拟构建一个可移植的分布式的开发平台已经不是梦了。

浙公网安备 33010602011771号