|
Docker入门笔记(3) – image和container
docker最简单的运行关系是这样的
镜像仓库和镜像/registry and image
registry是docker镜像的仓库。默认仓库是https://registry.hub.docker.com/。
镜像(image)是存放在registry里的。
我们可以直接在这里获取到centos、ubuntu等操作系统的镜像。这种系统镜像一般用来做二次定制,定制私有业务。
此外还有一些具体定制的镜像,比如tomcat、apache、nginx、mysql、mongodb、redis等。这些镜像的操作系统都裁剪的很小,所以一些简单需求直接拿这些镜像来用,会方便一些。centos、ubuntu这些系统基础镜像大小都在200M以上,而像busybox、flannel这些具体定制的镜像都不到50M。
以镜像为基础运行一个容器/run a container from image
我先拉取一个busybox镜像下来。
root@docker:~# docker pull busybox
latest: Pulling from busybox
511136ea3c5a: Pulling fs layer
511136ea3c5a: Download complete
df7546f9f060: Download complete
ea13149945cb: Download complete
4986bf8c1536: Download complete
Status: Downloaded newer image for busybox:latest
root@docker:~# docker images
REPOSITORY TAG IMAGE>
busybox latest 4986bf8c1536 7 weeks ago 2.433 MB
busybox buildroot-2014.02 4986bf8c1536 7 weeks ago 2.433 MB
root@docker:~#
可以看到busybox这种定制版本的镜像就很小,才3M不到。以这个镜像为基础运行一个contaienr:
root@docker:~# docker run -it busybox
/ # whoami
root
/ # date
Sat Feb 21 06:07:57 UTC 2015
/ # uname -r
3.13.0-32-generic
/ #
我们可以登陆 https://registry.hub.docker.com/ 很直观的查询有哪些可用的镜像以及使用方法。
我比较常用的镜像有
- centos:centos6
- tomcat:7
- mongo:2
container 状态
启动另外一个终端,查看container状态:
root@docker:~# docker ps
CONTAINER>
861856052a59 busybox:buildroot-2014.02 "/bin/sh" 10 seconds ago Up 10 seconds evil_newton
这时候输入exit或者直接ctrl+D可以退出这个container。这之后container会变成exited状态,并不会停留在后台执行。也就是说,container默认不会自动销毁。
# root@docker:~# docker ps
CONTAINER>
root@docker:~# docker ps -a
CONTAINER>
861856052a59 busybox:buildroot-2014.02 "/bin/sh" 3 minutes ago Exited (0) 4 seconds ago evil_newton
root@docker:~#
- image只是一个文件,运行起来之后的东西叫做container
- 一个image可以启动多个contaienr
- 每个container之间的读写变更不会相互影响
- container的读写变更不会影响到image
- 默认请款下,contaienr退出后会保存在磁盘上,不会自动销毁
- docker ps只能查看up状态的contaienr,要查看所有状态的container需要加 -a 参数
上面docker run命令,加了-i -t 两个参数。-i保证交互式输入。-t表示分配tty终端。这两个都和交互式输入输出有关系,默认加上即可,和本主题无关,我不想深究。大家在后期可以试试不加这两个参数的效果,对比一下。现在对比,除了无法输入输出,其他应该体验不出来。这个话题以后也许会再讨论。
前台和后台
上面通过 -i -t 的方式把 container 挂到终端上运行。这个只是在学习和打包 image 的时候会用到。如果是在线上业务中,把 contaienr 直接作为后台程序运行会更合适点。使用参数 -d 就行了。
root@docker:~# docker run -it -d busybox
0976249c0af6baab618043187ce067faba27832e8cf85a7d434ba6b2c25256aa
root@docker:~# docker ps
CONTAINER>
0976249c0af6 busybox:buildroot-2014.02 "/bin/sh" 3 seconds ago Up 2 seconds angry_archimedes
root@docker:~#
-d 后 busybox 不会在前台运行,docker直接给出 container>
网络服务相关的 container
基本所有业务都是需要通过网络对外提供服务的。所以我们可以通过 docker run -p 参数来实现。
docker run -p 80,在主机上找一个随机端口和 container 的 80 端口做映射(个人觉得比较没用)
docker run -P,在主机上找对应的若干个随机端口,和 image 文件指定的 expose 端口做映射(个人觉得比较没用)
docker run -p 10080:80,把主机的 10080 端口和 contaienr的 80 端口做映射。这时候业务要通过主机IP访问 container 里的 80 端口业务,要访问的可是 10080 端口。
docker run -p 192.168.0.10:10080:80,把主机的 192.168.0.10 IP的 10080 端口和 container 里的 80 端口做映射。
docker run -p -p -p,如果有多个端口需要映射,可以写多次 -p 参数。
root@docker:~# docker run -p 80:80 -p 23:23 -d -it busybox
13af89b8ef87c857cd1efb88f8fd5b8ffeca3faea691bcaa73c224fcc126183d
root@docker:~# docker ps
CONTAINER>
13af89b8ef87 busybox:buildroot-2014.02 "/bin/sh" 4 seconds ago Up 4 seconds 0.0.0.0:23->23/tcp, 0.0.0.0:80->80/tcp fervent_bohr
root@docker:~# netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 916/sshd
tcp6 0 0 :::23 :::* LISTEN 1780/docker-proxy
tcp6 0 0 :::80 :::* LISTEN 1789/docker-proxy
tcp6 0 0 :::22 :::* LISTEN 916/sshd
大家观察下上面输出。
为什么我的 container 总是退出?
docker run 一个 container 的时候,最后都需要加一个 CMD 参数,表示我 container 要启动什么程序。一旦这个程序退出或者挂到后台,就会导致整个 container 退出结束。从经验上看,下面涵盖了大多数情况:
- 程序无法启动
- 没有指定正确的程序路径或者程序不存在
- 启动程序的参数正确,比如没有这个参数
- 程序配置文件有错误
- 程序默认挂到后台执行了
比如我们执行 docker run -it -d busybox,其实 busybox 有一个默认的 CMD 值,是 /bin/sh ,也就是等同于 docker run -it -d busybox /bin/sh 。这两句命令是一样的。 /bin/sh 这个程序会一直等待键盘输入,所以不会退出。
定制自己需要的镜像
基于 container 进行 commit
光有基础系统的 image 只能玩一玩,没什么实际意义。我们尝试定制一个有自己功能的 image。
创建一个 container ,并且进入 container 中进行操作:
docker run -it busybox /bin/sh
在 container 中创建文件 /usr/bin/run.sh
root@docker:~# docker run -it busybox /bin/sh
/ # pwd
/
/ # vi /usr/bin/run.sh
内容如下:
#!/bin/sh
COUNT=0
while(true); do
COUNT=$(($COUNT+1))
echo $COUNT
sleep 2
done
授予执行权限:
chmod 755 /usr/bin/run.sh
测试,直接输入命令 run.sh 执行,可见终端每2秒就会输出一个计数,并且永不退出(while(true))。
/ # run.sh
1
2
3
4
5
6
...
+ C退出脚本,再exit或者 + D退出 container 。这时候可以通过 docker ps -a 看到 container 处于 exitted 状态,并且获得 container>
docker commit d3 cst05001/study
可以把该 container 提交为 docker 默认镜像仓库下,名为 cst05001/study 的镜像。不过这只是一个标记,镜像只存在于本地,并未真正的传到镜像服务器,只能本地使用。
root@docker:~# docker images
REPOSITORY TAG IMAGE>
cst05001/study latest a836bfbda876 2 minutes ago 2.433 MB
busybox buildroot-2014.02 4986bf8c1536 7 weeks ago 2.433 MB
busybox latest 4986bf8c1536 7 weeks ago 2.433 MB
我们尝试运行我们定制的这个镜像:
root@docker:~# docker run -it cst05001/study run.sh
1
2
3
...
成功。
Dockerfile(推荐)
通过 Dockerfile 进行镜像定制是在生产环境更高效更稳定的方法。不过我会放到以后再表。
push image
之前有说,我们定制的镜像并未传送到镜像服务器。如果希望共享出这个镜像给多台服务器使用,则需要把镜像推送到镜像服务器上(registry)。步骤大致如下:
- 在镜像服务器上注册自己的账号,创建自己的仓库(如果是自己创建的registry可以略过这一步)
- docker login,输入账号、密码、邮箱三个信息进行登陆验证
- docker push <镜像名(tag)全程>
比如我们提交刚才的 cst05001/study,则可以这么做
root@docker:~# docker login
Username: cst05001
Password:
Email: 65141838@qq.com
Login Succeeded
root@docker:~# docker push cst05001/study
The push refers to a repository [cst05001/study] (len: 1)
Sending image list
Pushing repository cst05001/study (1 tags)
511136ea3c5a: Image already pushed, skipping
df7546f9f060: Image already pushed, skipping
ea13149945cb: Image already pushed, skipping
4986bf8c1536: Image already pushed, skipping
a836bfbda876: Image successfully pushed
Pushing tag for rev [a836bfbda876] on {https://cdn-registry-1.docker.io/v1/repositories/cst05001/study/tags/latest}
现在我们就可以在全球所有接入互联网的机器上直接通过命令
docker pull cst05001/study
获取这个镜像,或者直接用命令
docker run cst05001/study run.sh
获取并运行这个镜像了。
第三方 registry
由于一些不方便讲的原因,在大陆地区使用官方 registry 经常会有下面几个问题
- pull速度慢
- pull失败
- push速度慢
- push失败
- 各种奇怪问题
所以就催生了第三方的 registry。我比较信赖的国内 registry 有docker.cn,最近刚发现改名成 https://containerops.cn/ 了。这个 registry 曾经缓存了 docker 官方 registry 的所有内容,据说一星期更新一次。用了 又拍云 的加速服务,还可以,实测大概两三百kbytes/s。可是改版后官方镜像不见了。所以如果你懒得搭建自己的私有registry,可以直接用他的。
推送镜像到 containerops.cn
前提是已经在 containerops.cn 注册了账号,并且创建了镜像库。登陆账号(如果你已经登陆了,可以略过这个步骤)。我偷个懒,把刚才的 cst05001/study 镜像做一个别名,也绑定到 docker。是的,image 名称也起到指定 registry地址、仓库的作用。再然后推送镜像就可以了。
root@docker:~# docker login containerops.cn
Username: cst05001
Password:
Email: 65141838@qq.com
Login Succeeded
root@docker:~# docker tag cst05001/study containerops.cn/cst05001/study
root@docker:~# docker push containerops.cn/cst05001/study
The push refers to a repository [containerops.cn/cst05001/study] (len: 1)
Sending image list
Pushing repository containerops.cn/cst05001/study (1 tags)
Image 511136ea3c5a already pushed, skipping
Image df7546f9f060 already pushed, skipping
Image 4986bf8c1536 already pushed, skipping
Image ea13149945cb already pushed, skipping
a836bfbda876: Image successfully pushed
Pushing tag for rev [a836bfbda876] on {https://containerops.cn/v1/repositories/cst05001/study/tags/latest}
root@docker:~#
部署私有 registry
这个是挺重要的一件事情,我会单独开一章来表。
小建议
请执行 docker run –help ,把每一个参数都一个字一个字的读一遍。这样挺好的。
问题
本文在使用第三方 registry 的时候,漏了一个重要的点没有说。如果有亲自测试,一定会遇到,并且不解决不行,但是会有明显的报错以及提示解决方法。请问这是什么? |
|
|