核心概念"/>
Docker核心概念
Docker解决的核心问题是利用LXC实现类似于VM的功能,从而利用更加节省的硬件资源提供给用户更多的计算资源。
1.1 核心概念
在开始使用Docker之前,首先要了解Docker中的概念和它们之间的关系,否则直接上手可能会搞得一头雾水。Docker中最重要的三个概念就是:镜像、容器、库。
- 镜像:是一个包含了应用程序和其运行时依赖环境的只读文件。
- 容器:它是构建容器的模板,通过一个镜像我们可以构造出很多相互独立但运行环境一样的容器。
- 库:Docker提供了Hub来保存公有或私有的镜像,也允许第三方搭建。
下面就是典型的Docker工作流,从这张图中能清晰地理解这三个重要概念之间的关系。本节接下来就根据这个Workflow逐一介绍常用的操作。
1.2 搜索下载镜像
首先用docker search [keyword]
命令查看Docker Hub上都有哪些镜像可以下载,search后可以用通配符表示关键字:
cdai ~ $ docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating s... 2179 [OK]
ubuntu-upstart Upstart is an event-based replacement for ... 31 [OK]
torusware/speedus-ubuntu Always updated official Ubuntu docker imag... 25 [OK]
tleyden5iwx/ubuntu-cuda Ubuntu 14.04 with CUDA drivers pre-installed 17 [OK]
ubuntu-debootstrap debootstrap --variant=minbase --components... 12 [OK]
neurodebian NeuroDebian provides neuroscience research... 11 [OK] ...
接下来用docker pull [repository/url:tag]
命令下载镜像。因为从官方Docker Hub下载非常慢,所以这里从国内的镜像站,速度非常快。(注:后面会讲到用docker run命令创建容器,其实如果镜像不存在Docker会自动去下载,这里为了学习pull命令所以手动下载镜像)
cdai ~ $ docker pull dl.dockerpool:5000/ubuntu:14.04
cdai ~ $ docker pull dl.dockerpool:5000/centos:latest
下载完成后,就可以用docker images
查看本地都有哪些镜像。这里的REPOSITORY列可能有三种类型:
- [namespace/ubuntu]:当你在Docker Hub上注册账户时,账户名就自动成为你的namespace,它是用来区分不同用户的镜像的。
- [ubuntu]:这种只有仓库名的可以认为它属于顶级namespace,这种仓库只用于官方的镜像。
- [dl.dockerpool:5000/ubuntu]:URL路径表示镜像是放置在第三方搭建的Hub上。
cdai ~ $ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
dl.dockerpool:5000/ubuntu 14.04 5506de2b643b 10 months ago 199.3 MB
dl.dockerpool:5000/centos latest 87e5b6b3ccc1 11 months ago 224 MB
如果想要查看镜像的详细信息,可以用docker inspect [image-id]
命令查看。(注:下面容器一节会看到,这个命令也能够用来查看容器的详细信息)
cdai ~ $ docker inspect 5506de2b643b
[{"Architecture": "amd64","Author": "","Comment": "","Config": {"AttachStderr": false,"AttachStdin": false,"AttachStdout": false,"Cmd": ["/bin/bash"],...},"Container": "201ae89099c20e577dd9c60cb9199c2dac0688d49efa676bf3eeb859666294bd","ContainerConfig": {"AttachStderr": false,"AttachStdin": false,"AttachStdout": false,...},"Created": "2014-10-23T23:53:59.03271073Z","DockerVersion": "1.3.0","Id": "5506de2b643be1e6febbf3b8a240760c6843244c41e12aa2f60ccbb7153d17f5","Os": "linux","Parent": "22093c35d77bb609b9257ffb2640845ec05018e3d96cb939f68d0e19127f1723","Size": 0
}]
1.3 创建启动容器
了解了镜像的基本操作后,我们就可以创建容器了。首先用docker create
创建容器或者用docker run [repository:tag]
创建并运行容器。容器可以分为两种类型:
- 交互型容器:前台运行,可以通过控制台与容器交互。如果创建该容器的终端被关闭,则容器就变为停止状态。此外,在容器控制台中输入exit或者通过
docker stop
或docker kill
也能终止容器。 - 后台型容器:后台运行,创建启动之后就与终端无关了,需要用
docker stop
或docker kill
来终止。
说明:因为我的老本子是32位的,即便从第三方Hub安装了镜像也都是64位的无法使用,所以这里的例子都使用第一节中手动构建出的32位Ubuntu镜像。
首先我们创建运行一个交互型容器试试,在容器的控制台里简单的输出个”Hello,Docker”。怎么样?Docker容器非常轻量级,启动非常快吧!用docker ps
可以查看正在运行的容器,用docker ps -a
查看所有容器,包括未启动的容器。(-l和-n=x能列出最后创建的一个或x个容器)
cdai ~ $ docker run -i -t 32bit/ubuntu:14.04 /bin/bash
root@328aa6305d82:/# echo "Hello, Docker!"
Hello, Docker!
root@328aa6305d82:/# exit
exitcdai ~ $ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
328aa6305d82 32bit/ubuntu:14.04 /bin/bash 24 seconds ago Exited (0) 4 seconds ago stupefied_curie
现在再创建运行一个后台型容器。可以用restart参数设置容器异常退出时自动重启:”always”不管什么返回码都尝试重启容器;”on-failure:x”则只在返回码非0时才会重启,并尝试x次。最后可以接上一个容器启动后执行的命令。这里为了做一个例子学习,所以用一个循环每隔5秒输出”hello world”。(Docker 1.3后提供了docker exec
用于在容器运行之后中途启动另一个程序)
cdai ~ $ docker run -d 32bit/ubuntu:14.04 /bin/bash -c "while true; do echo hello world; sleep 5; done"
5c40590cc23cfa02bd6c0220da77b601973f01f8bc430baca22315ef68d81e44
cdai ~ $ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c40590cc23c 32bit/ubuntu:14.04 /bin/bash -c while 5 seconds ago Up 5 seconds evil_bartik
现在容器已经在后台运行起来了,没有控制台我们怎样能查看容器的状态呢?Docker提供了一些很实用的容器内操作命令,例如docker logs [container-name]
能够查看容器内标准输出流中的内容,docker top [container-name]
查看容器中的所有进程。下面就用这两个命令查看一下刚才启动的容器运行得怎么样了?注意:启动容器时如果没用name参数指定容器名称的话,Docker会自动生成一个,下面的命令都用这个名称作为参数。
cdai ~ $ docker logs -f evil_bartik
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
^C
cdai ~ $ docker top evil_bartik
UID PID PPID C STIME TTY TIME CMD
root 26803 1700 0 21:54 ? 00:00:00 /bin/bash -c while true; do echo hello world; sleep 5; done
root 26859 26803 0 21:55 ? 00:00:00 sleep 5
可以看到我们的容器运行良好,循环体在不断输出”hello world”到输出流中。之前学习镜像说过docker inspect
也可以用于容器,现在就用它查看一下容器的详细信息。从输出可以清晰地看到启动命令、环境参数、网络等信息。
cdai ~ $ docker inspect evil_bartik
[{"Args": ["-c","while true; do echo hello world; sleep 5; done"],"Config": {"AttachStderr": false,"AttachStdin": false,"AttachStdout": false,"Hostname": "5c40590cc23c","Image": "32bit/ubuntu:14.04",...},"Created": "2015-09-03T13:54:03.389202827Z","Driver": "aufs",..."MountLabel": "","Name": "/evil_bartik","NetworkSettings": {"Bridge": "docker0","Gateway": "172.17.42.1","IPAddress": "172.17.0.5","IPPrefixLen": 16,"PortMapping": null,"Ports": {}},...
}]
容器学习的差不多了,现在就把它停下来了吧。之前说过,对于后台型容器有docker stop [container-name]
和docker kill [container-name]
两种方法。那它们有什么区别呢?前者会给容器内的进程发送SIGTERM信号,默认行为是容器退出,当然容器内的程序也可以捕获该信号后自行处理。而后者会给容器内的进程发送SIGKILL信号,导致容器直接退出。
cdai ~ $ docker stop evil_bartik
evil_bartik
cdai ~ $ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5c40590cc23c 32bit/ubuntu:14.04 /bin/bash -c while 3 minutes ago Exited (-1) 5 seconds ago evil_bartik
328aa6305d82 32bit/ubuntu:14.04 /bin/bash 11 minutes ago Exited (0) 11 minutes ago stupefied_curie
1.4 制作上传镜像
本地镜像的制作有使用commit命令和编写Dockerfile两种方式。下面就先分别介绍这两种制作方式,然后学习一下如何把我们自己制作的本地镜像上传到Docker Hub上。
1.4.1 用commit制作镜像
首先启动我们之前创建的交互型容器stupefied_curie。启动成功后会发现我们并没有进入容器的控制台,这时就要使用之前没有介绍的一个容器内使用的命令,attach命令,帮我们重新进入一个已启动容器的控制台。(注意:执行attach后,要按一次回车才会出现容器的控制台界面。而且后台型容器是无法attach的)
cdai ~ $ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
328aa6305d82 32bit/ubuntu:14.04 /bin/bash 10 hours ago Exited (0) 10 hours ago stupefied_curie
attach上之后我们就可以在容器内操作了,这里我们安装一个Sqlite数据库并保存一个文本文件,准备好要制作成本地镜像的容器。本以为一切会很顺利,结果却碰到了容器内无法上网的问题,因为默认容器与宿主主机是桥接的关系需要配置一些DNS等设置。上网查了一下最简单的方法就是改一下网络模式,让容器使用与宿主主机一样的网络栈。这里重新创建一个交互型容器,网络模式使用host模式。
cdai ~ $ docker run -i -t --net="host" 32bit/ubuntu:14.04 /bin/bash
root@cdai:/# apt-get install sqlite3
Reading package lists... Done
Building dependency tree
Reading state information... Done
Suggested packages:sqlite3-doc
The following NEW packages will be installed:sqlite3
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 28.3 kB of archives.
After this operation, 161 kB of additional disk space will be used.
Get:1 / trusty-updates/main sqlite3 i386 3.8.2-1ubuntu2.1 [28.3 kB]
Fetched 28.3 kB in 2s (10.8 kB/s)
Selecting previously unselected package sqlite3.
(Reading database ... 11535 files and directories currently installed.)
Preparing to unpack .../sqlite3_3.8.2-1ubuntu2.1_i386.deb ...
Unpacking sqlite3 (3.8.2-1ubuntu2.1) ...
Setting up sqlite3 (3.8.2-1ubuntu2.1) ...
root@cdai:/# echo "test docker commit" >> hellodocker
root@cdai:/# exit
exit
现在就可以用docker commit [container-id]
命令将前面准备好的容器制作成镜像了!(为什么有的命令用ID有的用name呢?)执行完成后,就能查我们的镜像已安装到本地库了。这里还发现了一个问题,就是基于32位镜像创建的容器,再制作成镜像好像又是64位了,启动时又会报”finalize namespace drop capabilities operation not permitted”错误,:(
cdai ~ $ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1718e35463ff 32bit/ubuntu:14.04 /bin/bash 53 seconds ago Exited (0) 8 seconds ago boring_babbage cdai ~ $ docker commit --author="cdai" 1718e35463ff cdai/sqlite3:v1
e10622157a5df7c82bdf148bda021e0fe312c153852f7a6c765c216d4d636ecb
cdai ~ $ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
cdai/sqlite3 v1 e10622157a5d 6 seconds ago 321.8 MB
32bit/ubuntu 14.04 c062cc00654e 11 hours ago 295.3 MB
1.4.2 用Dockerfile制作镜像
上面我们在容器的控制台上手动执行一些操作,而Dockerfile是一种更加透明并且可重复的制作方式,因为我们不是手动执行操作,而是将所有操作用Docker提供的命令和语法编写到Dockerfile中。命令名全部大写,常用的Dockerfile命令有:
- FROM:指定扩展自哪个父级镜像。
- RUN:执行命令修改镜像。例如RUN apt-get update和RUN [“apt-get”, “update”]。前者在/bin/sh中执行命令,后者直接使用系统调用exec执行。
- EXPOSE:指明容器内进程对外开放的端口。也可以在容器启动时用-p参数开放一些在Dockerfile里没有列出的端口。
- ADD:添加宿主主机文件、文件夹或URL指定资源到镜像中。
- ENV:设置容器运行的环境变量。
- USER:为容器的运行以及Dockerfile后面的命令指定用户。
其他命令还有:MAINTAINER声明作者信息、WORKDIR指定工作目录(最后一个会作为容器启动后的工作目录)、VOLUME挂载文件、CMD和ENTRYPOINT指定容器启动后执行的命令、ONBUILD指定一些命令在当前镜像构建时不会执行,而是在子镜像构建时触发。
了解了这些常用的命令,下面就可以开始编写Dockerfile了。注意:Dockerfile文件名默认就叫”Dockerfile”,否则执行build命令时Docker会找不到。编写好后,执行docker build .
就可以开始构建了,每一条Dockerfile的命令都相当于构建出一个临时镜像,最后一步会生成最终的目标镜像。
cdai $ ls
-rw-r--r-- 1 root root 17 Sep 4 09:08 abc.txt
-rw-r--r-- 1 root root 188 Sep 4 09:08 Dockerfile
cdai $ cat Dockerfile
FROM 32bit/ubuntu:14.04
MAINTAINER cdai "XXX@163"
USER root
RUN apt-get install -y nginx
EXPOSE 80 8080
RUN touch test.txt
ADD abc.txt .
ENTRYPOINT ["ls"]
CMD ["-a", "-l"]cdai $ docker build -t cdai/nginx:v1 .
Sending build context to Docker daemon 3.584 kB
Sending build context to Docker daemon
Step 0 : FROM 32bit/ubuntu:14.04---> c062cc00654e
Step 1 : MAINTAINER cdai "dc_726@163"---> Running in 53ece79679ed---> 979f81286bbe
Removing intermediate container 53ece79679ed
Step 2 : USER root---> Running in f5d29e4895e5---> 4965bbb8d8cd
Removing intermediate container f5d29e4895e5
Step 3 : RUN apt-get install -y nginx---> Running in d4e46baff94a
Reading package lists...
Building dependency tree...
Reading state information...
The following extra packages will be installed:fontconfig-config fonts-dejavu-core geoip-database libfontconfig1libfreetype6 libgd3 libgeoip1 libjbig0 libjpeg-turbo8 libjpeg8 libtiff5libvpx1 libx11-6 libx11-data libxau6 libxcb1 libxdmcp6 libxml2 libxpm4libxslt1.1 nginx-common nginx-core sgml-base xml-core
Suggested packages:libgd-tools geoip-bin fcgiwrap nginx-doc sgml-base-doc debhelper...
Setting up nginx (1.4.6-1ubuntu3.3) ...---> 73f5d909ac29
Removing intermediate container d4e46baff94a
Step 4 : EXPOSE 80 8080---> Running in 4333d2f3c58c---> b693316fb774
Removing intermediate container 4333d2f3c58c
Step 5 : RUN touch test.txt---> Running in 815dfbfb2005...
1.4.3 上传镜像到Hub
首先用docker login
命令输入我们在Docker Hub的登录信息,Docker会将其保存到~/.dockercfg中。
cdai $ docker login
Username: cdai
Password:
Email: XXX@163
Login Succeeded
cdai $ cat ~/.dockercfg
{"/":{"auth":"XXXXaToxXXXXXXlEYiE=","email":"XXX@163"}}cdai $ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
cdai/sqlite3 v1 e10622157a5d 37 minutes ago 321.8 MB
32bit/ubuntu 14.04 c062cc00654e 11 hours ago 295.3 MBcdai $ docker push cdai/sqlite3:v1
The push refers to a repository [cdai/sqlite3] (len: 1)
Sending image list
Pushing repository cdai/sqlite3 (1 tags)
c062cc00654e: Buffering to disk
更多推荐
Docker核心概念
发布评论