Docker有两个概念需要搞清楚,镜像与容器。

1
2
镜像是从网上docker pub上拉取下来的镜像,拉取下来后可以使用docker run命令进行运行。
# dockerhub 是官方构建的一个镜像仓库,类似github一样,上面累积了许多人上传制作的镜像,有官方,有的是用户上传的,任何人都可自由下载。
1
容器是将镜像运行在一个容器中

Registry

1
2
3
用户可以在自己的数据中心搭建私有的registry,也可以从官方使用docker官方的registry也就是docker hub.
它是一个公共的镜像仓库,供用户下载和使用,dockerhub中有两种库。
用户仓库和顶层库,用户仓库是有私人创建的,顶层使用docker公司负责维护的。

常用操作命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
docker images #查看从docker hub上下载到本地的镜像
docker search #镜像名#从docker hub上搜索镜像
docker pull #从docker registry中拉取镜像
docker push #将本地制作好的镜像推送到docker hub
docker rm 容器id #删除容器命令
docker rmi 镜像id #删除镜像
docker stop $(docker ps -a) #批量停止容器
docker rm $(docker ps -a) # 批量删除容器
docker rm $(docker ps -a|awk '{print $1}'|cut -f 1 -d "C") # 批量删除容器
docker stop $(docker ps -q) & docker rm $(docker ps -aq) #both
###ps:docker rm 与docker rmi 都可以加 -f强制删除,需要注意的是如果删除镜像报错,如果基于镜像启动的容器存在,则无法直接删除,需要先删除容器再删除镜像。
docker inspect # 查看镜像和容器的详细信息
docker ps # 查看容器相关的信息,状态 选项 -a 列出所有容器的的状态 -l 列出最新的状态
docker commit <container_id> <some_name> # 可以将一个容器固化为一个新的镜像,通过commit将镜像保存起来,也就是可以将一个环境配配置好的容器,保存,以后用到在拿出来使用。
docker run -it -v --volumes-from --name --rm --privileged 镜像名字 # 以交互式运行容器 --name 只是一个名称,可以不加 --rm docker容器退出时将自动删除,注意如果容器运行在后台模式是不能带--rm的.需要映射多个端口使用多个-p 选项
docker run 镜像名字 echo “hello world” # 在容器的shell中输出helloworld
docker logs 容器id #显示容器的标准输出
docker attach 容器id #重新进入关闭的容器
docker network inspect bridge

docker命令结构:

首先有两个方面,一个是docker镜像制作端,一个是用户使用端类似C/S 架构。

使用docker build命令结合dockerfile可以创建管理镜像,创建完后可以push到docker hub。

用户可以通过从网上拉取制作好的镜像,拉取到本地,运行容器。

使用docker pull时,可以从官方docker hub中的官方镜像库,其他公共库,私人仓库,拉取镜像资源,同时也可以拉取私有服务器中获取镜像资源,只需指定特定的库名,或服务器地址即可。

如何临时退出一个正在交互的容器,而不是终止

1
按ctrl-p+ctrl-q   #ctrl -c 是终止停止进程

构建docker镜像应该遵循的原则,请参考官方文档,dockerfile最佳实践:

尽量选取满足需求但较小的基础系统镜像,例如大部分时候可以选择 debian:wheezy 或 debian:jessie 镜像,仅有不足百兆大小;

清理编译生成文件、安装包的缓存等临时文件; 安装各个软件时候要指定准确的版本号,并避免引入不需要的依赖;

从安全角度考虑,应用要尽量使用系统的库和依赖; 如果安装应用时候需要配置一些特殊的环境变量,

在安装后要还原不需要保持 的变量值;

使用 Dockerfile 创建镜像时候要添加 .dockerignore 文件或使用干净的工作目 录。

在构建docker容器时可以控制容器占用系统资源,调整系统硬件资源,例如cpu,内存,io等。

查看容器映射出来的端口。

1
docker ps -f name=nginx

查看容器内应用监听的端口:

1
docker exec -ti global_nginx_1 ss -lntp

制作镜像

两种办法:1.使用Dockerfile,使用docker commit 将容器提交保存为镜像.##最好使用Dockerfile来构建镜像,不推荐docker commit方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
首先编辑一个空白的文本文件命名为DockerfIle,每一个指令的前缀都必须是大写的。
FROM centos #从centos 这个镜像文件中构建,from字段必须是第一个,可以有多个from
在文件中可以写入运行命令使其在docker容器中运行
RUN echo ’hello world‘ ##在容器中运行的指令
CMD ##
ENV ##后续的指令可以调用变量 ${variable_name}
WORKDIR ##
MAINTAINER ## dockerfile会根据上下文执行的命令,使用缓存,如果修改了使用者名称,将刷新缓存
EXPOSE ## 端口宣告
ADD ##
COPY ##
docker build -t 给镜像一个名称 . #注意,最后有个点,这条命令会读取当前目录下的所有文件以及目录和Dockerfile文件,建议创建新目录来build

之后使用 docker images 就可以看到自己建立的镜像了,使用docker history 镜像id 就可以查看到刚刚容器的输出结果了。注意这个创建的镜像是不可以开启新的容器的 官方的解释 "Notice the new changed-ubuntu image does not have its own copies of every layer. As can be seen in the diagram below, the new image is sharing its four underlying layers with the ubuntu:15.04 image."
并且使用 docker history 可以看到刚刚通过文件输出镜像的大小只有11b,这种只是个共享图像层。
一旦你构建或创建了一个新的镜像,你可以使用 docker push 命令将镜像推送到 Docker Hub 。这样你就可以分享你的镜像了,镜像可以是公开的,或者你可以把镜像添加到你的私有仓库中。

Docker Volumes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
docker volumes 是一个存储卷,它可以使宿主机与容器里面共享数据,这个数据卷可以是系统文件上的任何一个目录,你可以挂在任意个Volumes 到容器里,多个容器也可以共享一个或多个数据量。
docker run --volumes-from
如果你有一些持久化的数据, 并且想在不同的container之间共享这些数据, 或者想在一些没有持久化的container中使用,
最好的方法就是使用 Data Volumn Container,
在把数据mount到你的container里.(译者:如开篇译者提到的docker的container是无状态的,
也就是说标记状态的数据,例如:数据库数据, 应用程序的log 等等, 是不应该放到container里的, 而是放到 Data Volume
Container里, 这点和funcational programming很像, 所以我喜欢把一般的docker container 叫做
functional container用来区分 data volume container )
这里的意思相当于有个最简洁的容器来专门跑存储容器,之后的启动的容器都可以使用 docker run --volumes-from 从存储数据容器中来实现数据的共享。
$ docker run -d -v /dbdata --name dbdata training/postgres

这样做之后就可以通过 --volumes-from 把 /dbdata mount到其他的container里了

$ docker run -d --volumes-from dbdata --name db1 training/postgres

还可以继续共享到另外一个container里

$ docker run -d --volumes-from dbdata --name db2 training/postgres

-volumes-from 可以多次使用来 mount 多个conatainer里的多个volumes。

这个操作是链式的, 我们在db1 中通过 --volumes-from mount进来的 volume可以继续被其他container使用

$ docker run -d --name db3 --volumes-from db1 training/postgres

(译者:
这里我们不是直接使用 volume container, 而是使用db1 这个functional container 把volume
挂载到另外一个 funcational container上的,所谓的链式就是 dbdata -> db1 -> db3)

如果你把所有mount volumes的container都移除掉, 包括初始化的那个 dbdata container, volume才会被移除掉。通过这个属性可以方便的升级升级数据或者在不同container间migrate数据.

备份、恢复和移植数据卷

Volume的另外一个用处就是备份、恢复和migrate数据。 具体的做法如下,使用 --volumes-from 来创建一个新的container mount这个volume

$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

>
这里我们启动了一个新的container,
从 dbdata 挂载了一个volume。同时挂载了一个本地目录到这个container里。最后我们通过一个 tar命令把 dbdata 里的数据备份到了 /backup 里。命令结束并且停止这个container后我们就在本地得到了一个备份的数据.

(译者: 这里使用的 ubuntu container, 就是为了把volume中的数据打包备份到host的某一个目录里。)

备份的数据可以恢复到这个container, 或者其他使用这个volume的container。首先创建一个container

$ sudo docker run -v /dbdata --name dbdata2 ubuntu

> 之后un-tar备份文件到 data volume 里

$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar

你可以使用你喜欢的工具加上上面的技术来自动备份,迁移和恢复数据

实践:在Docker容器中运行web应用

1
2
3
4
首先docker pull nginx 或者制作好web应用的镜像.
docker run -idt -p 80:80 -v /docker/download/:/data/ download:1 #以后台进程运行
docker exec 容器id nginx #使用docker exec执行nginx 启动命令
docker top #查看容器内的进程运行状态

开启动一个长时间运行的后台进程

1
2
3
a=$(docker run -d centos /bin/bash -c "while true; do echo hello world; sleep 1; done")

docker logs $a ##将会看到有hello world

删除Docker镜像

首先要保证有权限对Docker镜像或者容器进行操作,具体做法参见进入前文安装部分。

1
2
3
4
5
6
7
8
9
10
11
# 停止所有容器
$ docker stop $(docker ps -a -q)

# 删除指定镜像
$ docker rmi $image

# 删除无标示镜像,即id为<None>的镜像
$ docker rmi $(docker images | grep "^<none>" | awk "{print $3}")

# 删除所有镜像
$ docker rmi $(docker images -q)

在Docker构建nginx容器 #在构建Dockerfile时应在空目录下构建

构建dockerfile

1
2
3
4
5
6
7
8
9
10
11
cat<<\EOF > Dockerfile 
# Nginx
#
# Version 1.0
FROM centos
MAINTAINER djluo <dj.luo@baoyugame.com>
RUN rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
RUN yum -y install nginx; yum clean all
EOF
#通过Dockerfile在容器中安装nginx
docker build -t nginx:1.0 . #-t 只是个版本名称

进入容器修改配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bash-4.2# 
bash-4.2# rm conf.d/{default.conf,example_ssl.conf}
bash-4.2# rm -f /etc/nginx/{koi-utf,koi-win,scgi_params,uwsgi_params,win-utf}
bash-4.2# cat<<\EOF > /etc/nginx/conf.d/download.conf
server {
listen 80;
server_name localhost;
root /data/html;
access_log /data/logs/download.log;
location / {
autoindex on;
}
}
EOF
bash-4.2# mkdir -p /data/{html,logs}
bash-4.2# /usr/sbin/nginx -t
bash-4.2# exit

制作成镜像commit:

1
2
3
docker ps -l # 获取最新的一个容器信息,通常就是上面操作的了。
docker commit -a "djluo <dj.luo@baoyugame.com>" -m "用于docker build的下载环境" 07d7a871cf32 download:1
docker rm 07d7a871cf32 # 删除容器

构建Nginx的主目录和日志目录:

1
2
mkdir -p ~/docker/download/{html,logs}
echo "Hi" > ~/docker/download/html/index.html

正式运行下载环境的容器:需要映射端口,公网访问

1
2
docker run -d -p 80:80 --name download -v /docker/download/:/data/ download:1 /usr/sbin/nginx
#将docker容器里的80端口映射到宿主机的80,好让外网访问,-v共享存储卷,将宿主机的目录数据挂载到容器里 并且启动nginx
1
2
3
4
5
正确的用法:应该是分为2个容器,应用容器和管理容器。
应用容器:跑具体的应用,如nginx、java、php等。将应用数据放到VOULME中。
管理容器:跑SSHD,并挂载上应用容器的数据VOULME。随心所欲的操作吧。
不过有些应用的重启、重新导入配置等,可能需要到容器外操作
docker守护进进程(服务端)默认以unixsocket方式启动,如果需要用到远程调用需要使用remoteapi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
以下是一个RUN格式正确的指导,显示所有apt-get 建议。

RUN apt-get update && apt-get install -y \
aufs-tools \
automake \
build-essential \
curl \
dpkg-sig \
libcap-dev \
libsqlite3-dev \
mercurial \
reprepro \
ruby1.9.1 \
ruby1.9.1-dev \
s3cmd=1.1.* \
&& rm -rf /var/lib/apt/lists/*

####################ENTRYPOINT###############################
ENTRYPOINT ["executable", "param1", "param2"] (exec表格,首选)

docker 默认本地的仓库目录,存储着push的镜像。

这个目录默认是100g,超过了将会push失败,所以建议定时清理。

从容器内拷贝文件到主机上

1
docker cp <containerId>:/file/path/within/container /host/path/target
1
2
3
4
5
docker 镜像导入和导出
导出镜像
docker save -o centos7.tar centos
导入本地镜像
sudo docker load --input centos7.tar