docker应用
安装
sudo yum install docker
启动 docker 进程
$ sudo service docker start
Docker 默认开机启动
$ sudo chkconfig docker on
下载最新的镜像,如 centos
sudo docker pull centos
查看镜像信息
$ sudo docker images centos
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
centos latest 0b443ba03958 2 hours ago 297.6 MB
运行容器,如果正常运行,你将会获得一个简单的 bash 提示,输入 exit 来退出。
sudo docker run -ti centos /bin/bash
CentOS 项目为开发者提供了大量的的示例镜像
交互式容器,-t 表示在新容器内指定一个伪终端或终端,-i表示允许我们对容器内的 (STDIN) 进行交互。
sudo docker run -t -i ubuntu:14.04 /bin/bash
root@af8bae53bdd3:/#
守护进程,-d 标识告诉 docker 在容器内以后台进程模式运行。docker返回的一个很长的字符串,这个长的字符串叫做容器ID(container ID)。它对于每一个容器来说都是唯一的,所以我们可以使用它。
$ sudo docker run -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
1e5535038e285177d5214659a068137486f96ee5c2e85a4ac52dc83f2ebe4147
注意:容器 ID 是有点长并且非常的笨拙,稍后我们会看到一个短点的 ID,某些方面来说它是容器 ID 的简化版。
查询 docker 进程的所有容器
sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e5535038e28 ubuntu:14.04 /bin/sh -c 'while tr 2 minutes ago Up 1 minute insane_babbage
docker ps 命令会返回一些有用的信息,这里包括一个短的容器 ID:1e5535038e28。
我们还可以查看到构建容器时使用的镜像,ubuntu:14.04,当命令运行之后,容器的状态随之改变并且被系统自动分配了名称 insane_babbage。
命令会查看容器内的标准输出
$ sudo docker logs insane_babbage
hello world
hello world
. . .
停止容器
$ sudo docker stop insane_babbage
insane_babbage
使用容器
docker 客户端
$ docker run -i -t ubuntu /bin/bash
运行一个web应用
$ sudo docker run -d -P training/webapp python app.py
-P 标识通知 Docker 将容器内部使用的网络端口映射到我们使用的主机上。我们指定了 training/web 镜像。我们创建容器的时候使用的是这个预先构建好的镜像,并且这个镜像已经包含了简单的 Python Flask web 应用程序。
$ sudo docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse
-l 返回最后启动容器的详细信息。
PORTS
0.0.0.0:49155->5000/tcp
在这种情况下,Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 49155 上。
Docker 能够很容易的配置和绑定网络端口。在最后一个例子中 -P 标识(flags)是 -p 5000 的缩写,它将会把容器内部的 5000 端口映射到本地 Docker。主机的高位端口上(这个端口的通常范围是 32768 至 61000)。我们也可以指定 -p 标识来绑定指定端口。
$ sudo docker run -d -p 5000:5000 training/webapp python app.py
查看网络端口
$ sudo docker port nostalgic_morse 5000
0.0.0.0:49155
查看WEB应用程序容器的进程
$ sudo docker top nostalgic_morse
PID USER COMMAND
854 root python app.py
查看WEB应用程序日志
$ sudo docker logs -f nostalgic_morse
* Running on http://0.0.0.0:5000/
10.0.2.2 - - [23/May/2014 20:16:31] "GET / HTTP/1.1" 200 -
10.0.2.2 - - [23/May/2014 20:16:31] "GET /favicon.ico HTTP/1.1" 404 -
查看Docker的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。
$ sudo docker inspect nostalgic_morse
[{
"ID": "bc533791f3f500b280a9626688bc79e342e3ea0d528efe3a86a51ecb28ea20",
"Created": "2014-05-26T05:52:40.808952951Z",
"Path": "python",
"Args": [
"app.py"
],
"Config": {
"Hostname": "bc533791f3f5",
"Domainname": "",
"User": "",
. . .
我们也可以针对我们想要的信息进行过滤,例如,返回容器的 IP 地址,
$ sudo docker inspect -f '{{ .NetworkSettings.IPAddress }}' nostalgic_morse
172.17.0.5
停止/重启/删除WEB应用容器
$ sudo docker stop nostalgic_morse
$ sudo docker start nostalgic_morse # $ sudo docker restart nostalgic_morse
$ sudo docker rm nostalgic_morse
docker镜像
列出本地主机上的镜像
sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
training/webapp latest fc77f57ad303 3 weeks ago 280.5 MB
ubuntu 13.10 5e019ab7bf6d 4 weeks ago 180 MB
ubuntu saucy 5e019ab7bf6d 4 weeks ago 180 MB
ubuntu 12.04 74fe38d11401 4 weeks ago 209.6 MB
查找镜像
- Docker Hub
- sudo docker search sinatra
创建我们自己的镜像
- 我们可以从已经创建的容器中更新镜像,并且提交这个镜像。
- 我们可以使用 Dockerfile 指令来创建一个新的镜像。
更新并且提交更改
使用镜像来创建一个容器
$ sudo docker run -t -i training/sinatra /bin/bash
root@0b2616b0e5a8:/# 已创建容器ID 0b2616b0e5a8
使用 gem 来安装 json
root@0b2616b0e5a8:/# gem install json
输入 exit命令来退出这个容器
$ sudo docker commit -m="Added json gem" -a="Kate Smith" 0b2616b0e5a8 ouruser/sinatra:v2
4f177bd27a9ff0f6dc2a830403925b5360bfe0b93d476f7fc3231110e7f71b1c
-m 标识我们指定提交的信息,就像你提交一个版本控制。-a 标识允许对我们的更新来指定一个作者。我们也指定了想要创建的新镜像容器来源 (我们先前记录的ID) 0b2616b0e5a8 和 我们指定要创建的目标镜像。
使用新镜像
$ sudo docker run -t -i ouruser/sinatra:v2 /bin/bash
root@78e82f680994:/#
使用 docker commit 命令能够非常简单的扩展镜像。但是它有点麻烦,并且在一个团队中也不能够轻易的共享它的开发过程。为解决这个问题,我们使用一个新的命令 docker build , 从零开始来创建一个新的镜像。
为此,我们需要创建一个 Dockerfile 文件,其中包含一组指令来告诉 Docker 如何构建我们的镜像。
$ mkdir sinatra
$ cd sinatra
$ touch Dockerfile
编写:
# This is a comment
FROM ubuntu:14.04
MAINTAINER Kate Smith <ksmith@example.com>
RUN apt-get update && apt-get install -y ruby ruby-dev
RUN gem install sinatra
每一个指令的前缀都必须是大写的。构建镜像
docker build -t ouruser/sinatra:v2 .
我们使用 docker build 命令并指定 -t 标识(flag)来标示属于 ouruser ,镜像名称为 sinatra,标签是 v2。
如果 Dockerfile 在我们当前目录下,我们可以使用 . 来指定 Dockerfile。
Dockerfile 中的每一条命令都一步一步的被执行。我们会看到每一步都会创建一个新的容器,在容器内部运行指令并且提交更改 - 就像我们之前使用的 docker commit 一样。当所有的指令执行完成之后,我们会得到97feabe5d2ed 镜像(也帮助标记为 ouruser/sinatra:v2), 然后所有中间容器会被清除。
连接容器
网络端口映射
$ sudo docker run -d -P training/webapp python app.py
$ sudo docker run -d -p 5000:5000 training/webapp python app.py
$ sudo docker run -d -p 127.0.0.1:5001:5002 training/webapp python app.py
# 绑定容器端口5002到宿主机动态端口,并且让localhost访问
$ sudo docker run -d -p 127.0.0.1::5002 training/webapp python app.py
# 绑定UDP端口
$ sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
Docker容器连接
docker有一个连接系统允许将多个容器连接在一起,共享连接信息。docker连接会创建一个父子关系,其中父容器可以看到子容器的信息。
容器命名
$ sudo docker run -d -P --name web training/webapp python app.py
$ sudo docker inspect -f "{{ .Name }}" aed84ee21bde
/web
容器连接
$ sudo docker run -d --name db training/postgres
$ sudo docker run -d -P --name web --link db:db training/webapp python app.py
我们使用training/postgres容器创建一个新的容器。容器是PostgreSQL数据库,创建一个web容器来连接db容器。
--link name:alias
name是我们连接容器的名字,alias是link的别名。
查看容器连接
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
349169744e49 training/postgres:latest su postgres -c '/usr About a minute ago Up About a minute 5432/tcp db
aed84ee21bde training/webapp:latest python app.py 16 hours ago Up 2 minutes 0.0.0.0:49154->5000/tcp db/web,web
我们还在名字列中可以看到web容器也显示db/web。这告诉我们web容器和db容器是父/子关系。
我们连接容器做什么?我们发现连接的两个容器是父子关系。这里的父容器是db可以访问子容器web。为此docker在容器之间打开一个安全连接隧道不需要暴露任何端口在容器外部。你会注意到当你启动db容器的时候我们没有使用-P或者-p标识。我们连接容器的时候我们不需要通过网络给PostgreSQL数据库开放端口。
Docker在父容器中开放子容器连接信息有两种方法:
- 环境变量
- 更新/etc/hosts文件。
- 查看列表容器的环境变量
$ sudo docker run --rm --name web2 --link db:db training/webapp env
. . .
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5000_TCP=tcp://172.17.0.5:5432
DB_PORT_5000_TCP_PROTO=tcp
DB_PORT_5000_TCP_PORT=5432
DB_PORT_5000_TCP_ADDR=172.17.0.5
. . .
每个前缀变量是DB_填充我们指定的别名。如果我们的别名是db1,前缀别名就是DB1_。您可以使用这些环境变量来配置您的应用程序连接到你的数据库db容器。该连接时安全、私有的,只能在web容器和db容器之间通信。
docker除了环境变量,可以添加信息到父主机的/etc/hosts
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7 aed84ee21bde
. . .
172.17.0.5 db
一项是web容器用容器ID作为主机名字。第二项是使用别名引用IP地址连接数据库容器。现在我们试试ping这个主机:
root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping db
PING db (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
我们可以利用这个主机项配置应用程序来使用我们的db容器。
注:你可以使用一个父容器连接多个子容器。例如,我们可以有多个web容器连接到我们的db数据库容器。
管理容器数据
Docker管理数据的两种主要的方法:
- 数据卷
- 数据卷容器
数据卷是指在存在于一个或多个容器中的特定目录,此目录能够通过Union File System提供一些用于持续存储或共享数据的特性。
- 数据卷可在容器之间共享或重用
- 数据卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
添加一个数据卷,docker run命令中使用-v标识来给容器内添加一个数据卷,你也可以在一次docker run命令中多次使用-v标识挂载多个数据卷。
$ sudo docker run -d -P --name web -v /webapp training/webapp python app.py
这会在容器内部创建一个新的卷/webapp。类似的,你可以在Dockerfile中使用VOLUME指令来给创建的镜像添加一个或多个数据卷。
挂载一个主机目录作为卷
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
把本地目录/src/webapp挂载到容器的/opt/webapp目录。
docker默认情况下是对数据卷有读写权限,添加了ro选项来限制它只读。
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
如果你想要容器之间数据共享,或者从非持久化容器中使用一些持久化数据,最好创建一个指定名称的数据卷容器,然后用它来挂载数据。
让我们创建一个指定名称的数据卷容器,实质就是挂载一个数据卷。
$ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres
可以在另外一个容器使用--volumes-from标识,通过刚刚创建的数据卷容器来挂载对应的数据卷。
$ sudo docker run -d --volumes-from dbdata --name db1 training/postgres
$ sudo docker run -d --volumes-from dbdata --name db2 training/postgres
$ sudo docker run -d --name db3 --volumes-from db1 training/postgres
也可以对一个容器使用多个--volumes-from标识,来将多个数据卷桥接到这个容器中。
数据卷容器是可以进行链式扩展的,之前的dbdata数据卷依次挂载到了dbdata 、db1和db2容器,我们还可以使用这样的方式来将数据卷挂载到新的容器db3。
启动了一个挂载dbdata卷的新容器,并且挂载了一个本地目录作为/backup卷。最后,我们通过使用tar命令将dbdata卷的内容备份到容器中的/backup目录下的backup.tar文件中。当命令完成或者容器停止,我们会留下我们的dbdata卷的备份。
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
恢复数据
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar