Docker 101(一) --- 容器
随着云计算服务,Docker容器类工具也开始大行其道。虽然早有耳闻,一直不了解其应用场景。最近折腾应用的服务化。服务器和应用迁移过程中,手动处理的方式太low。想到如何借助Docker部署和发布应用,或许是一个比较好的方式。下面是Docker初探的一些手记。可以大致熟悉docker的概念和操作。
安装
Docker早期的版本,对于mac非常不友好。安装还需要配合virtraulbox虚拟机。最新的版本则只需要安装一个dmg。然后神马docker engine
, docker-compose
和docker-machine
都一应尽有了。
安装完毕docker之后,点击docker的app即可启动。运行docker info
命令可以查docker的安装和运行状况。
镜像和容器
使用docker饶不过两个概念,镜像和容器。为了易于理解,暂且把镜像看成一个操作系统,只不过这个操作系统是静态的,还没有运行的文件。实际上镜像是特殊的文件系统,充分利用了UnionFS技术的分成存储架构。所谓的容器,可以理解为运行时的镜像。
假如启动了虚拟机来安装软件,为了防止安装有问题的软件,先打了一个快照进行备份。然后每安装一个软件,就打一个快照备份。这些备份的文件,就可以看成是一个个镜像。如果某个软件有问题,你需要从快照中恢复系统。选择一个快照(镜像)之后恢复系统,这个恢复的就可以看成是容器,即运行时的镜像。
当然,docker实际上实现的镜像和容器,并不是上述虚拟机快照的方式。只不国他们的使用方式和效果类似罢了,初次接触docker,暂且这么理解。
安装镜像
既然镜像是一些文件,那么从什么地方获取这些文件呢?Docker的公司提供了一个集中式的仓库---docker hub,存储了大量官方或三方的镜像文件。这个网站就类似github一样,可以自定义仓库,然后push或者pull镜像文件。下面安装一个最简单的linux系统的镜像。
运行docker images
即可查看本地导入docker的镜像。如果全新安装docker,那么首次运行该命令将看不到任何镜像文件。
☁ docker docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
使用docker pull
可以下载并导入一个镜像
☁ docker docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
7520415ce762: Pull complete
Digest: sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f
Status: Downloaded newer image for busybox:latest
☁ docker docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 00f017a8c2a6 2 weeks ago 1.11 MB
docker pull 命令会向仓库网站请求镜像文件,默认是(docker hub)。下载完毕之后可以看到我们导入了busybox的镜像。镜像一般由仓库,标签,镜像id,大小等信息。每一个镜像文件都是一个仓库,可以给这个仓库打tag。镜像id是镜像的唯一标识符,不能重复。引用镜像既可以其镜像id,也可以使用仓库:标签
的方式,例如busybox:latest
,默认的标签都是latest
。当不写标签的时候,docker会指默认的标签。
启动容器
载入镜像之后,我们就可以创建并启动容器了。使用docker run
命令启动容器。
☁ docker docker run --name hello -it busybox /bin/sh
/ # ls
bin dev etc home proc root sys tmp usr var
/ # echo 'hello world'
hello world
run
命令有不少参数,--name
表示给容器起一个名字以方便我们识别和引用。-it
其实是两个参数,分别指--interactive
和--tty
,表示开启一个交互式的终端服务,就行登录远程服务器一样登录容器。
run 命令会检查本地的镜像,如果本地没有就会去镜像仓库(默认是docker hub)中下载,然后再启动容器。
容器状态
重启的状态大致分为三种种,创建(Created), 运行(Up),退出(Exited)。打开另外一个命令行,使用docker ps
命令查看容器的状态。
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3d8f08bef033 busybox "/bin/sh" 3 minutes ago Up 3 minutes hello
可以看见和查看镜像一样类似。每个容器也有一个容器唯一标识的id,既可以使用容器id也可以使用nama参数引用容器。此时的容器状态是正在运行。
使用docker stop
命令停止容器
☁ docker docker stop hello
hello
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
☁ docker docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3d8f08bef033 busybox "/bin/sh" 5 minutes ago Exited (137) 8 seconds ago hello
☁ docker docker ps -a -q
3d8f08bef
停止容器之后,可以给ps
命令添加-a
和-q
参数,前者用来查看所有容器的状态,包含已经退出运行的容器(Exited)。后者可以返回容器的id。当需要批量删除容器的时候,这个id参数很重要。
以
-it
方式登录容器的终端,运行exit
也会退出并停止容器。
容器有停止,当然就有启动,重启。
☁ docker docker start 3d8f08bef033
3d8f08bef033
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3d8f08bef033 busybox "/bin/sh" 8 minutes ago Up 2 seconds hello
☁ docker docker restart hello
hello
上面演示了除了容器name之外,使用容器的id引用容器。
容器删除
创建了运行的容器,可以启动也可以关闭。当容器不再使用的时候,我们可以删除容器。删除容器前,务必保证先关闭容器,否则删除失败。
☁ docker docker rm hello
Error response from daemon: You cannot remove a running container 3d8f08bef03361155c062acc08ee0a7cfd9bc2d3914d1627e14f192ca409fc50. Stop the container before attempting removal or use -f
☁ docker docker stop hello
hello
☁ docker docker rm hello
hello
☁ docker docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
进入容器
我们启动了容器,有时候启动了容器,然后还需要进入容器做一些动作。下面再创建一个新的容器:
☁ docker docker run --name app -it busybox /bin/sh
/ #
/ # exit
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
☁ docker docker start app
app
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ece3ac215e3 busybox "/bin/sh" About a minute ago Up 2 seconds app
☁ docker docker exec -it app /bin/sh
/ # ls
bin dev etc home proc root sys tmp usr var
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ece3ac215e3 busybox "/bin/sh" 2 minutes ago Up About a minute app
使用exit
退出容器,然后再用start
命令启动容器,最后使用exec
命令进入容器,最后再退出。exec进入再退出和run进入退出不一样,前者不会关闭容器,后者会关闭容器。当然,如果容器尚未启动,docker exec
是无法进入容器。
容器创建与守护运行方式
我们使用docker run
命令创建并启动了容器。其实还有一个命令只创建容器,但不启动容器。
☁ docker docker create --name newapp busybox echo "hello new app"
3c5b2e39e2203052b8ee72742a1ed06f65e4c71244c98f64f8fd778bc050e171
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
☁ docker docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c5b2e39e220 busybox "echo 'hello new app'" 7 seconds ago Created newapp
☁ docker docker logs newapp
☁ docker docker start newapp
newapp
☁ docker docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3c5b2e39e220 busybox "echo 'hello new app'" 28 seconds ago Exited (0) 3 seconds ago newapp
☁ docker docker logs newapp
hello new app
上面的命令中,首先使用docker create
创建了一个新的容器newapp
,同时传递一个sh运行命令echo "hello new app"
。刚创建的时候,看不到运行的容器的状态,实际上容器创建之后尚未启动,只是Created
状态,因此也无法中docker logs
中看到容器的输出。
当我们启动容器的时候,执行了echo命令,因此可以看到logs有执行的输出。可是容器执行完毕echo命令之后,就退出了。这其实很好理解,例如我们运行一个脚本,脚本运行完毕自然就退出了。只不过现在运行的脚本在容器中而已,完成任务软件自然就退出。除非容器中的脚本或者软件命令是以非daemon方式运行,或者执行一个永不退出的命令。
☁ docker docker create --name always_run busybox tail -f /dev/null
c5c6bb0acbee5d3037558defdaa54968cca3f94083dc765603caa1095f5d7466
☁ docker docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c5c6bb0acbee busybox "tail -f /dev/null" 4 seconds ago Created always_run
☁ docker docker start always_run
newapp
☁ docker docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c5c6bb0acbee busybox "tail -f /dev/null" 12 seconds ago Up 3 seconds always_run
上面介绍的只是容器内软件的运行方式。实际上docker的run命令要比create常用,而run命令执行创建容器并运行,我们会登录这个容器中,一旦exit,容器就停止了。如果需要启动容器的时候,还需要再运行start命令,为此可以给docker指定参数,让docker的进程以daemon方式运行。
☁ docker docker run --name deamon_app -d busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
4fb992fa3dce0c46ddabda4493924a5f0ff2c01a5cb72c1951ce6496fcb81c4f
☁ docker docker logs -f deamon_app
hello world
hello world
hello world
查看容器的运行状态
docker ps
可以看见docker的容器列表及其大致状态。此外,docker还提供了stats
和top
用来查看docker的容器的更详细状态:
☁ docker docker top deamon_app
PID USER TIME COMMAND
13253 root 0:00 /bin/sh -c while true; do echo hello world; sleep 1; done
13275 root 0:00 sleep 1
☁ docker docker stats deamon_app
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
deamon_app 0.06% 480 KiB / 1.952 GiB 0.02% 578 B / 648 B 0 B / 0 B 2
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
deamon_app 0.05% 468 KiB / 1.952 GiB 0.02% 578 B / 648 B 0 B / 0 B 2
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
top
可以查看docker里容器运行的进程状态,stats
则可以看到更详细的信息,包含CPU,内存,网络等。并且top
只能查看运行的容器,stats
没有限制。
关于容器更详细的状态,可以使用docker inspect
命令。
总结
Docker其实是一种基于LXC实现的软件虚拟化技术。主要由仓库,镜像和容器组成完整的软件构建方式。仓库是存储docker镜像的文件库,镜像是分层的包含完成操作系统的文件,可以理解为操作系统的快照。容器则是基于镜像创建的操作系统运行环境。容器的状态分为Created,Up,Eixited。
我们介绍了不少命令用于操作容器。接下来,再探索一下关于镜像相关的操作。