Docker容器在开发中的使用。

Docker概念

Docker是一个开源的应用容器引擎,基于Go语言并遵从 Apache2.0 协议开源。
Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似iPhone的app),更重要的是容器性能开销极低。

Docker原理

Docker是什么
  Docker 利用 Linux 核心中的资源分脱机制,例如 cgroups,以及 Linux 核心名字空间(name space),来创建独立的软件容器(containers),属于操作系统层面的虚拟化技术。由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。Docker 在容器的基础上进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护,使得其比虚拟机技术更为轻便、快捷。Docker 可以在单一 Linux 实体下运作,避免因为创建一个虚拟机而造成的额外负担。

Docker主要包含三个基本概念,分别是镜像、容器和仓库,理解了这三个概念,就理解了Docker的整个生命周期。以下简要总结一下这三点,详细介绍可以移步Docker 从入门到实践对应章节。

镜像:Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
容器:容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间容器可以被。创建、启动、停止、删除和暂停等等,说到镜像与容器之间的关系,可以类比面向对象程序设计中的类和实例。
仓库:镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。一个 Docker Registry 中可以包含多个仓库;每个仓库可以包含多个标签;每个标签对应一个镜像,其中标签可以理解为镜像的版本号。

Unbunt16环境搭建

1、安装

cmd
1
sudo apt-get install docker.io

2、卸载

cmd
1
sudo apt-get remove docker docker-engine docker.io

3、为当前用户添加docker的root权限

cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
# 1.如果没有创建docker用户组,则需要先创建一个docket用户组。
sudo groupadd docker
# 2.将指定的用户添加到docker用户组。
sudo usermod -aG docker userName
# 3.重启docker服务
sudo service docker restart
# sudo /etc/init.d/docker restart
# 或者重新登陆docker用户
sudo systemctl restart docker
# 4.切换当前回话到docker组或者关闭当前回话重新打开终端。
newgrp - docker //切换到docker用户组
# 5.测试
docker run hello-world

4、更改Docker数据存储的位置
  Docker所下载的image, 生成的containers, 甚至包括持久化数据用的vollume, 默认都会保存到 /var/lib/docker目录下。

cmd
1
2
3
4
5
6
7
8
9
10
11
12
# 停止docker服务
# sudo sysemctl stop docker
sudo service docker stop
# 更改配置文件
# 配置文件是默认不存在的, 默认位置如下, 当然也可以换成其他路径
# 填入以下内容, 指向新的位置
sudo vim /etc/docker/daemon.json
{
"graph":"/mnt/cryptfs/docker"
}
# 启动服务即可
sudo service docker start

5、共享目录
  在docker run的时候, 使用 –vollume设置一个内外的共享目录, 有点类似虚拟机的那种共享目录。创建vollume持久化磁盘,使用docker vollme先创建一个数据磁盘, 然后再docker run的时候, 把这个磁盘或多个mount到某个目录上。
NOTE:docker vollume的默认存储还是再/var/lib/docker下

Docker使用教程

菜鸟教程Docker参考
菜鸟教程Docker命令

直接执行

cmd
1
2
3
4
5
docker run ubuntu:15.10 /bin/echo "Hello world"
# @docker: Docker 的二进制执行文件。
# @run: 与前面的 docker 组合来运行一个容器。
# @ubuntu:15.10 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
# @/bin/echo "Hello world": 在启动的容器里执行的命令

带终端执行

cmd
1
2
3
4
5
6
7
8
9
10
docker run -i -t ubuntu:15.10 /bin/bash
# @-t: 在新容器内指定一个伪终端或终端。
# @-i: 允许你对容器内的标准输入 (STDIN) 进行交互。
# @-d: 不进入容器后台执行。
# @-P: 将容器内部使用的网络端口映射到我们使用的主机上。
# @-p: 参数来设置不一样的端口。
# @-d: 后台执行
# @-ipc=host: 增加主机与容器共享内存用或者--shm-size
# docker run -d -p 5000:5000 training/webapp python app.py
# @exit 退出

显示日志

cmd
1
2
3
4
docker logs docker_id
# @-t:
# @-f:
# 显示日志

显示所有容器

cmd
1
2
3
4
docker ps
# @-a: 显示所有
# @-s: 显示大小
# 显示所有容器

获取镜像

cmd
1
docker pull ubuntu

启动停止镜像

cmd
1
2
docker start docker_id
# docker start $(docker ps -aq)

停止镜像

cmd
1
2
docker stop docker_id
# docker stop $(docker ps -aq)

重启镜像

cmd
1
2
docker restart docker_id
# docker restart $(docker ps -aq)

删除镜像

cmd
1
2
docker rm docker_id
# docker rm $(docker ps -aq)

进入容器

cmd
1
2
docker attach
docker exec:使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。

导出容器

cmd
1
2
docker export 1e560fca3906 > ubuntu.tar
# @ubuntu.tar: 导出容器名

导入容器快照

cmd
1
2
docker import - test/ubuntu:v1
# docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

列出镜像列表

cmd
1
docker images

查找镜像

查找镜像网址

cmd
1
docker search httpd

拖取镜像

cmd
1
docker pull 

删除镜像

cmd
1
docker rmi docker_id 

创建镜像

当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。
1、从已经创建的容器中更新镜像,并且提交这个镜像
2、使用 Dockerfile 指令来创建一个新的镜像

cmd
1
2
3
4
5
6
7
8
# 进入镜像
docker run -t -i ubuntu:15.10 /bin/bash
# docker commit 来提交容器副本
docker commit -m="has update" -a="runoob" e218edb10161 runoob/ubuntu:v2
# @-m: 提交的描述信息
# @-a: 指定镜像作者
# @e218edb10161:容器 ID
# @runoob/ubuntu:v2: 指定要创建的目标镜像名

从零构建镜像

1、创建Dockerfile的文件

Dockerfile
1
2
3
4
5
6
7
8
9
10
FROM    centos:6.7
MAINTAINER Fisher "fisher@sudops.com"

RUN /bin/echo 'root:123456' |chpasswd
RUN useradd runoob
RUN /bin/echo 'runoob:123456' |chpasswd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
EXPOSE 22
EXPOSE 80
CMD /usr/sbin/sshd -D

2、手动构建一个镜像

cmd
1
2
3
docker build -t runoob/centos:6.7 .
# @-t :指定要创建的目标镜像名
# @. :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径

设置镜像标签

cmd
1
2
3
4
docker tag 860c279d2fec runoob/centos:dev
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# @860c279d2fec:镜像ID
# @用户名称、用户名称、镜像源名(repository name)和新的标签名(tag)

容器命名

cmd
1
2
docker run -d -P --name runoob training/webapp python app.py
# @--name:镜像ID

新建网络

cmd
1
2
3
docker network create -d bridge test-net
# docker network COMMAND
# @--name:镜像ID

连接容器

cmd
1
2
3
4
# 容器1
docker run -itd --name test1 --network test-net ubuntu /bin/bash
# 容器2
docker run -itd --name test2 --network test-net ubuntu /bin/bash

Docker仓库管理

目前Docker官方维护了一个公共仓库Docker Hub

创建本地镜像

基本镜像

1、基于其他镜像修改镜像

cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Search镜像
docker search alpine
# Pull镜像
docker pull alpine
# 查看镜像
docker image ls
# 运行pull的镜像
docker run -itd alpine:latest /bin/sh
# 查看运行的容器
docker ps
# 复制文件到alpine镜像
docker cp filename alpine_docker_run_id:/root/
# docker commit 来提交容器副本
docker commit -m "has update" -a "runoob" lpine_docker_run_id runoob/ubuntu:v2
# @-m: 提交的描述信息
# @-a: 指定镜像作者
# @e218edb10161:容器 ID
# @runoob/ubuntu:v2: 指定要创建的目标镜像名

2、基于Dockerfile构建镜像

a、创建Dockerfile的文件

Dockerfile
1
2
3
4
5
6
7
8
9
10
FROM    centos:6.7
MAINTAINER Fisher "fisher@sudops.com"

RUN /bin/echo 'root:123456' |chpasswd
RUN useradd runoob
RUN /bin/echo 'runoob:123456' |chpasswd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local
EXPOSE 22
EXPOSE 80
CMD /usr/sbin/sshd -D
Dockerfile
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
FROM:定制的镜像都是基于 FROM 的镜像

RUN:用于执行后面跟着的命令行命令。

shell 格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。

exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test", "dev", "offline"] 等价于 RUN ./test dev offline

Dockerfile 的指令每执行一次都会在 docker 上新建一层。过多无意义的层,会造成镜像膨胀过大
FROM centos
RUN yum install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz

COPY:复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
格式:

COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/
COPY hom?.txt /mydir/
<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD:指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

CMD 在docker run 时运行。
RUN 是在 docker build。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

格式:
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...] # 如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是sh。

ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参

1、不传参运行
$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf

2、传参运行

$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

nginx -c /etc/nginx/new.conf
ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
ARG
构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

格式:
ARG <参数名>[=<默认值>]
VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:
避免重要的数据,因容器重启而丢失,这是非常致命的。
避免容器不断变大。
格式:

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

EXPOSE
仅仅只是声明端口。

作用:
帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
格式:

EXPOSE <端口1> [<端口2>...]
WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:
WORKDIR <工作目录路径>

USER
用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
格式:

USER <用户名>[:<用户组>]
HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
ONBUILD
用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:
ONBUILD <其它指令>

b、手动构建一个镜像

cmd
1
2
3
docker build -t runoob/centos:6.7 .
# @-t :指定要创建的目标镜像名
# @. :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径

设置镜像标签

cmd
1
2
3
4
docker tag 860c279d2fec runoob/centos:dev
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# @860c279d2fec:镜像ID
# @用户名称、用户名称、镜像源名(repository name)和新的标签名(tag)

登录和退出

cmd
1
2
3
4
# 登录
docker login
# 登出
docker logout

docker容器中文件的上传与下载

1、上传文件

cmd
1
docker cp /root/test.txt ecef8319d2c8:/root/

2、下载文件

cmd
1
docker cp ecef8319d2c8:/root/test.txt /root/

推送镜像

cmd
1
2
3
docker tag ubuntu:18.04 username/ubuntu:18.04
docker push username/ubuntu:18.04
docker search username/ubuntu