Docker概念

前言

为什么会有Docker的出现呢?可能很多不了解的人都会有这样的疑问。最近工作中有接触到Docker所以就有了这篇文章。

Docker 是世界领先的软件容器平台。
开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。
运维人员利用 Docker 可以在隔离容器中并行运行和管理应用,获得更好的计算密度。
企业利用 Docker 可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为 Linux 和 Windows Server 应用发布新功能。

为什么需要Docker?

1.环境(切换/配置)麻烦

一般我们写程序,能接触到好几个环境:

  • 自己写代码的环境叫做开发环境
  • 给测试去跑的环境叫做测试环境
  • 测试完可以对外使用的叫做生产环境

其实我们在学习编程中,很多时间都浪费在“环境”上:

  • 如果我现在重装了系统,我想要跑我的war/jar包,我得去安装一下JDK、Tomcat、MySQL等配置各种的环境变量才能跑起来。
  • 开开心心地跟着博主给出的步骤去写Demo,但总是有Bug。(这里我将版本/依赖也归纳在环境的范畴里边)。
  • 好不容易在测试环境下跑起来了,在生产环境就各种出错!
  • 跟着教学视频做分布式/集群的项目,跑一堆的虚拟机,每个虚拟机都要安装对应的环境。

2.应用之间需要隔离

比如我写了两个应用(网站),这两个应用部署在同一台服务器上,那可能会出现什么问题?

  • 如果一个应用出现了问题,导致CPU占100%。那另一个应用也会受到关联,跟着一起凉凉了。
  • 这两个应用是完全不同技术栈的应用,比如一个PHP,一个.NET。这两个应用各种的依赖软件都安装在同一个服务器上,可能就会造成各种冲突/无法兼容,这可能调试就非常麻烦了。

Docker是如何解决上述的问题

1.解决环境(切换/配置)

不知道大家有没有装过系统,比如说装Linux虚拟机,重装Windows系统,都是需要镜像的。

有了这个镜像,我们就可以运行这个镜像,来进行安装系统的操作(此处省略N个下一步),于是我们的系统就装好了。一般来说,我们去官方渠道下载的镜像,都是纯净的。比如去官方下载Windows镜像,装完后之后桌面只有一个回收站。

但有过了解装系统的同学可能就会知道,有的镜像装完可能还有360这些软件,但系统的的确确是变了。简单来说,就是这些镜像添加了其他的东西(比如360软件、腾讯、千千静听等等软件)。

Docker也是这种思路,可以将我们的想要的环境构建(打包)成一个镜像,然后我们可以推送(发布)到网上去。想要用这个环 境的时候,在网上拉取一份就好了。

有了Docker,我们在搭环境的时候,跟以前的方式就不一样了。

  • 之前:在开发环境构建出了一个war包,想跑到Linux下运行。我们得先在Linux下载好Java、Tomcat、MySQL,配置好对应的环境变量,将war包丢到Tomcat的webapps文件夹下,才能跑起来。
  • 现在:在Linux下直接拉取一份镜像(各种环境都配好了),将镜像运行起来,把war包丢进去就好了。

将Docker的镜像运行起来就是一两秒的事情而已,十分方便的。

2.解决应用之间隔离

说到这里,就得提出一个大家可能不认识的概念:LXC(Linux Containers)—>Linux容器。

Linux

在Linux内核中,提供了cgroups功能,来达成资源的区隔化。它同时也提供了名称空间(namespace)区隔化的功能,使应用程序看到的操作系统环境被区隔成独立区间,包括进程树,网络,用户id,以及挂载的文件系统。

简单来说就是:LXC是一个为Linux内核包含特征的用户接口。通过强大的API和简单的工具,它可以让Linux用户轻松的创建和托管系统或者应用程序容器。

虚拟机和Docker

我之前也是用过虚拟机,虚拟机也能实现对应用的隔离,安装特定的镜像也能抛出我们想要的环境。虚拟机已经发展了很久了。为什么我们还需要Docker呢?

虚拟机和Docker的区别

一句话总结:Docker容器比虚拟机轻量多了!

Docker可以干嘛?

  • 将一整套环境打包封装成镜像,无需重复配置环境,解决环境带来的种种问题。
  • Docker容器间是进程隔离的,谁也不会影响谁。

Docker 基本命令

Hello world

Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在一个容器内运行一个应用程序。

1
docker run ubuntu:15.10 /bin/echo "Hello world"

各个参数解析:

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

运行交互式的容器

我们通过 docker 的两个参数 -i -t,让 docker 运行的容器实现“对话”的能力:

1
2
docker run -i -t ubuntu:15.10 /bin/bash
root@0123ce188bd8:/#

各个参数解析:

  • -t:在新容器内指定一个伪终端。
  • -i: 允许你对容器内的标准输入 (STDIN) 进行交互。

注意第二行 root@0123ce188bd8:/#,此时我们已进入一个 ubuntu15.10 系统的容器

我们尝试在容器中运行命令 cat /proc/versionls分别查看当前系统的版本信息和当前目录下的文件列表

我们可以通过运行 exit 命令或者使用 CTRL+D 来退出容器。

1
2
3
root@0123ce188bd8:/#  exit
exit
root@runoob:~#

启动容器后台模式

使用一下命令创建一个以进程方式运行的容器

1
2
runoob@runoob:~$ docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63

在输出中,我们没有看到期望的 “hello world”,而是一串长字符

2b1b7a428627c51ab8810d541d759f072b4fc75487eed05812646b8534a2fe63

这个长字符串叫做容器 ID,对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。

首先,我们需要确认容器有在运行,可以通过 docker ps 来查看:

1
2
3
runoob@runoob:~$ docker ps
CONTAINER ID IMAGE COMMAND ...
5917eac21c36 ubuntu:15.10 "/bin/sh -c 'while t…" ...

输出详情介绍:

CONTAINER ID: 容器 ID。

IMAGE: 使用的镜像。

COMMAND: 启动容器时运行的命令。

CREATED: 容器的创建时间。

STATUS: 容器状态。

状态有7种:

  • created(已创建)
  • restarting(重启中)
  • running(运行中)
  • removing(迁移中)
  • paused(暂停)
  • exited(停止)
  • dead(死亡)

PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。

NAMES: 自动分配的容器名称。

在宿主主机内使用 docker logs 命令,查看容器内的标准输出:

1
runoob@runoob:~$ docker logs 2b1b7a428627

Docker容器使用

  • Docker:我们可以直接输入docker命令查看到Docker客户端的所有命令选项
1
runoob@runoob:~# docker
  • docker stats –help 更深入的了解指定的Docker命令使用方法
1
runoob@runoob:~# docker stats --help
  • docker pull ubuntu:我们可以使用docker pull 命令来载入ubuntu镜像
1
docker pull ubuntu
  • 启动容器,以下命令使用ubuntu镜像启动一个容器,参数为一命令行模式进入该容器:
1
docker run -it ubuntu /bin/bash

参数说明:

-i:交互式操作。

-t:终端

ubuntu:ubuntu 镜像。

/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

启动已停止运行的容器

  • 查看所有的容器命令如下:
1
docker ps -a

image-20200714104353774

  • 使用 docker start 启动一个已停止的容器:
1
$ docker start b750bbbcfd88

image-20200714104443037

  • 后台运行,在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的运行模式。
1
$ docker run -itd --name ubuntu-test ubuntu /bin/bash

image-20200714104607300

  • 停止一个容器
1
docker stop <容器 ID>

image-20200714104701993

  • restart容器
1
docker restart <容器 ID>
  • 进入容器

在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:

docker attach

docker exec:推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。

1
docker attach 1e560fca3906

注意: 如果从这个容器退出,会导致容器的停止。

docker exec:推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。

1
docker exec -it 243c32535da7 /bin/bash

注意: 如果从这个容器退出,不会导致容器的停止,这就是为什么推荐大家使用 docker exec 的原因。

更多参数说明请使用 docker exec –help 命令查看。

  • 导出容器
1
$ docker export 1e560fca3906 > ubuntu.tar

导出容器 1e560fca3906 快照到本地文件 ubuntu.tar。

  • 导入容器快照

可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:

1
$ cat docker/ubuntu.tar | docker import - test/ubuntu:v1

此外,也可以通过指定 URL 或者某个目录来导入,例如:

1
$ docker import http://example.com/exampleimage.tgz example/imagerepo
  • 删除容器
1
docker rm -f 1e560fca3906

下面的命令可以清理掉所有处于终止状态的容器。

1
$ docker container prune

运行一个web应用

前面我们运行的容器并没有一些什么特别的用处。

接下来让我们尝试使用 docker 构建一个 web 应用程序。

我们将在docker容器中运行一个 Python Flask 应用来运行一个web应用。

1
2
runoob@runoob:~# docker pull training/webapp  # 载入镜像
runoob@runoob:~# docker run -d -P training/webapp python app.py
  • 查看web 应用容器

使用 docker ps 来查看我们正在运行的容器:

1
2
3
runoob@runoob:~#  docker ps
CONTAINER ID IMAGE COMMAND ... PORTS
d3d5e39ed9d3 training/webapp "python app.py" ... 0.0.0.0:32769->5000/tcp

这里多了端口信息。

1
2
PORTS
0.0.0.0:32769->5000/tcp

Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 32769 上。

这时我们可以通过浏览器访问WEB应用

image-20200714105844095

我们也可以通过 -p 参数来设置不一样的端口:

1
runoob@runoob:~$ docker run -d -p 5000:5000 training/webapp python app.py
  • 网络端口的快捷方式

通过 docker ps 命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port,使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。

上面我们创建的 web 应用容器 ID 为 bf08b7f2cd89 名字为 wizardly_chandrasekhar

我可以使用 docker port bf08b7f2cd89docker port wizardly_chandrasekhar 来查看容器端口的映射情况。

1
2
3
4
runoob@runoob:~$ docker port bf08b7f2cd89
5000/tcp -> 0.0.0.0:5000
runoob@runoob:~$ docker port wizardly_chandrasekhar
5000/tcp -> 0.0.0.0:5000
  • 查看WEB应用程序日志

docker logs [ID或者名字] 可以查看容器内部的标准输出。

1
2
3
4
runoob@runoob:~$ docker logs -f bf08b7f2cd89
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.239.1 - - [09/May/2016 16:30:37] "GET / HTTP/1.1" 200 -
192.168.239.1 - - [09/May/2016 16:30:37] "GET /favicon.ico HTTP/1.1" 404 -

-f:docker logs 像使用 tail -f 一样来输出容器内部的标准输出。

从上面,我们可以看到应用程序使用的是 5000 端口并且能够查看到应用程序的访问日志。

  • 查看WEB应用程序容器的进程

我们还可以使用 docker top 来查看容器内部运行的进程

1
2
3
runoob@runoob:~$ docker top wizardly_chandrasekhar
UID PID PPID ... TIME CMD
root 23245 23228 ... 00:00:00 python app.py
  • 检查WEB应用程序

使用docker inspect 来查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
runoob@runoob:~$ docker inspect wizardly_chandrasekhar
[
{
"Id": "bf08b7f2cd897b5964943134aa6d373e355c286db9b9885b1f60b6e8f82b2b85",
"Created": "2018-09-17T01:41:26.174228707Z",
"Path": "python",
"Args": [
"app.py"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 23245,
"ExitCode": 0,
"Error": "",
"StartedAt": "2018-09-17T01:41:26.494185806Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
......
  • 停止WEB应用容器
1
2
runoob@runoob:~$ docker stop wizardly_chandrasekhar   
wizardly_chandrasekhar
  • 重启WEB应用容器

已经停止的容器,我们可以使用命令 docker start 来启动。

1
2
runoob@runoob:~$ docker start wizardly_chandrasekhar
wizardly_chandrasekhar
  • docker ps -l 查询最后一次创建的容器:
1
2
3
#  docker ps -l 
CONTAINER ID IMAGE PORTS NAMES
bf08b7f2cd89 training/webapp ... 0.0.0.0:5000->5000/tcp wizardly_chandrasekhar
  • 移除WEB应用容器

我们可以使用 docker rm 命令来删除不需要的容器

1
2
runoob@runoob:~$ docker rm wizardly_chandrasekhar  
wizardly_chandrasekhar

删除容器时,容器必须是停止状态,否则会报如下错误

1
2
runoob@runoob:~$ docker rm wizardly_chandrasekhar
Error response from daemon: You cannot remove a running container bf08b7f2cd897b5964943134aa6d373e355c286db9b9885b1f60b6e8f82b2b85. Stop the container before attempting removal or force remove

Docker镜像使用

当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。

  • 列出镜像列表

我们可以使用 docker images 来列出本地主机上的镜像。

1
2
3
4
5
6
7
8
9
10
runoob@runoob:~$ docker images           
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 14.04 90d5884b1ee0 5 days ago 188 MB
php 5.6 f40e9e0f10c8 9 days ago 444.8 MB
nginx latest 6f8d099c3adc 12 days ago 182.7 MB
mysql 5.6 f2e8d6c772c0 3 weeks ago 324.6 MB
httpd latest 02ef73cf1bc0 3 weeks ago 194.4 MB
ubuntu 15.10 4e3b13c8a266 4 weeks ago 136.3 MB
hello-world latest 690ed74de00f 6 months ago 960 B
training/webapp latest 6fae60ef3446 11 months ago 348.8 MB

各个选项说明:

REPOSITORY:表示镜像的仓库源

TAG:镜像的标签

IMAGE ID:镜像ID

CREATED:镜像创建时间

SIZE:镜像大小

  • 获取一个新的镜像
1
Crunoob@runoob:~$ docker pull ubuntu:13.10
  • 查找镜像
1
runoob@runoob:~$  docker search httpd
  • 使用镜像
1
runoob@runoob:~$ docker run httpd
  • 删除镜像

镜像删除使用 docker rmi 命令,比如我们删除 hello-world 镜像:

1
$ docker rmi hello-world

Docker DockerFile

什么是DockerFile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

使用Dockerfile定制镜像

1.下面以定制一个nginx镜像构建好的镜像内会有一个/usr/share/nginx/html/index.html文件

在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:

1
2
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html

2、FROM 和 RUN 指令的作用

FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。

RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

1
2
3
4
5
6
7
8
9
FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
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

开始构建镜像

在 Dockerfile 文件的存放目录下,执行构建动作。

以下示例,通过目录下的 Dockerfile 构建一个 nginx:test(镜像名称:镜像标签)。

:最后的 . 代表本次执行的上下文路径,

1
$ docker build -t nginx:test .

img

以上显示,说明已经构建成功。

上下文路径

上一节中,有提到指令最后一个 . 是上下文路径,那么什么是上下文路径呢?

$ docker build -t nginx:test .

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

Dockerfile基本结构

Dockerfile 由一行行命令语句组成,并且支持已 # 开头的注释行。

一般而言,Dockerfile 的内容分为四个部分:
基础镜像信息

维护者信息

镜像操作指令

容器启动时执行指令

Dockerfile完整demo

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
# This dockerfile demo for project build to docker images
# VERSION 2
# Author: Shawn_xiao
# Command format: Instruction [arguments / command] …
# 2018/10/10- firstversion: xiao
# 2018/10/11- chanege the tomcat version

# 第一行必须指定基础容器,建议使用aipln类型的小容器
FROM tomcat:8

# 维护者信息(可选)
MAINTAINER xiaojianjun xiaojianjun@tansun.com.cn

# LABEL (可选) 标签信息(自定义信息,多标签放一行)
LABEL app.maintainer=xiaojianjun
LABEL app.version="1.0" app.host='bestxiao.cn' description="这个app产品构建"

# ENV (可选)环境变量(指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持
ENV JAVA_HOME /opt/java_jdk/bin
ENV PG_VERSION 9.3.4
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

# USER (可选) 指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户,前面的RUN 不受影响
# RUN groupadd -r postgres && useradd -r -g postgres postgres
USER postgres

# WORKDIT 后续的 RUN、CMD、ENTRYPOINT 指令配置容器内的工作目录
WORKDIR /path/to/workdir

# ADD/COPY 将外部文件copy到容器中。区别是ADD可以使用URL,还可以是tar
# COPY只能使用dockerfile所在目录
# ADD <src> <dest>
# COPY <src> <dest>
COPY target/tomcat-release.war /usr/local/tomcat/webapps/

# RUN 镜像的操作指令
# RUN <command> [“executable”, “param1”, “param2”]。
RUN echo “deb http://archive.ubuntu.com/ubuntu/ raring main universe” >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN mkdir /opt/deploy/
RUN echo “\ndaemon off;” >> /etc/nginx/nginx.conf

# EXPOSE 容器启动后需要暴露的端口
EXPOSE 22 80 8443 8080

# VOLUME 本地或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。
#VOLUME ["/data"]
VOLUME ["/data/postgres", "/other/path/"]


# ENTRYPOINT 容器启动后执行命令,不会被docker run提供的参数覆盖,只能有一个ENTRYPOINT,
# 多个ENTRYPOINT,以最后一个为准
#ENTRYPOINT [“executable”, “param1”, “param2”]
#ENTRYPOINT command param param2
ENTRYPOINT echo "helloDocker"

# 容器启动时执行指令,每个 Dockerfile 只能有一条 CMD 命令
#CMD [“executable”, “param1”, “param2”] 使用 exec 执行,推荐方式。
#CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用。
#CMD [“param1”, “param2”] 提供给 ENTRYPOINT 的默认参数。
CMD /usr/sbin/nginx


# ONBUILD 配置当所创建的镜像作为其他新创建镜像的基础镜像时,所执行的操作指令。例如,Dockerfile 使用如下的内容创建了镜像 image-A。-- 很少使用

# ONBUILD ADD . /app/src
# ONBUILD RUN /usr/local/bin/python-build –dir /app/src

简短demo

1
2
3
4
5
6
7
8
9
10
FROM centos
LABEL version="1.0" description="centos7" by="测试"
ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install java-1.8.0-openjdk

EXPOSE 80

CMD echo "------success------OK------"
1
2
3
4
5
6
7
8
#指定镜像
FROM primetoninc/jdk:1.8
#拷贝宿主机的app.jar
COPY app.jar app.jar
#配置端口
EXPOSE 8080
#运行app.jar包
ENTRYPOINT exec java -jar app.jar

DockerFile关键指令

FROM

格式为 FROM 或 FROM:
Dockerfile 的第一条指令必须为 FROM 指令。并且,如果在同一个 Dockerfile 中创建多个镜像时,可以使用多个 FROM 指令。

1
2
# 第一行必须指定基础容器,这里的是tomcat8
FROM tomcat:8

MAINTAINER

格式为 MAINTAINER ,指定维护者信息。

注意:MAINTAINER 指令已经被抛弃,建议使用 LABEL 指令。

1
2
# 维护者信息(可选)建议用LABEL 指令
MAINTAINER xiaojianjun xiaojianjun@tansun.com.cn

LABEL

LABEL 指令为镜像添加标签。一个 LABEL 就是一个键值对,也可以一行指定多个键值对。

1
2
3
4
5
6
7
#多行指定信息
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \that label-values can span multiple lines."

#一行指定多个键值对
LABEL app.version="1.0" app.host='bestxiao.cn' description="这个app产品构建"

如果新添加的 LABEL 和已有的 LABEL 同名,则新值会覆盖掉旧值。

RUN

每条 RUN 指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。

1
RUN yum -y install java-1.8.0-openjdk

CMD

指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条 CMD 命令,只有最后一条会被执行。如果用户在启动容器时指定了要运行的命令,则会覆盖掉 CMD 指定的命令。

1
CMD echo "------success------OK------"

EXPOSE

告诉 Docker 服务,容器需要暴露的端口号,供互联系统使用。在启动容器时需要通过 -P 参数让 Docker 主机分配一个端口转发到指定的端口。使用 -p 参数则可以具体指定主机上哪个端口映射过来。

1
EXPOSE 22 80 8443 8080

ENV

格式为 ENV 。指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。

1
2
3
4
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

ADD

该命令将复制指定的 到容器中的 。其中 可以是 Dockerfile 所在目录的一个相对路径(文件或目录);也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。

1
ADD <src> <dest>

COPY

复制本地主机的 (为 Dockerfile 所在目录的相对路径,文件或目录) 为容器中的 。目标路径不存在时,会自动创建。当使用本地目录为源目录时,推荐使用 COPY。

1
COPY <src> <dest>

ENTRYPOINT

配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个 ENTRYPOINT 时,只有最后一个生效。

1
2
ENTRYPOINT [“executable”, “param1”, “param2”]
ENTRYPOINT command param1 param2 (shell 中执行)

VOLUME

使用 VOLUME 指令添加多个数据卷,创建一个可以从本地或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

1
2
VOLUME ["/data"]
VOLUME ["/data1", "/data2"]

USER

指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户

1
2
3
USER daemon

RUN groupadd -r postgres && useradd -r -g postgres postgres

WORKDIR

为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。

1
2
# WORKDIT 后续的 RUN、CMD、ENTRYPOINT 指令配置容器内的工作目录
WORKDIR /path/to/workdir

ONBUILD

配置当所创建的镜像作为其他新创建镜像的基础镜像时,所执行的操作指令

1
FROM image-A#automatically run the followingADD ONBUILD ADD . /app/srcONBUILD RUN /usr/local/bin/python-build –dir /app/src

如果基于 image-A 创建新的镜像时,新的 Dockerfile 中使用 FROM image-A 指定基础镜像时,会自动执行 ONBUILD 指令内容,等价于在后面添加了两条指令。

1
FROM image-A#automatically run the followingADD . /app/srcRUN /usr/local/bin/python-build –dir /app/src
文章目录
  1. 1. 前言
  2. 2. 为什么需要Docker?
    1. 2.1. 1.环境(切换/配置)麻烦
    2. 2.2. 2.应用之间需要隔离
    3. 2.3. Docker是如何解决上述的问题
    4. 2.4. 1.解决环境(切换/配置)
    5. 2.5. 2.解决应用之间隔离
  3. 3. 虚拟机和Docker
    1. 3.1. 虚拟机和Docker的区别
  4. 4. Docker 基本命令
    1. 4.1. Hello world
    2. 4.2. 运行交互式的容器
    3. 4.3. 启动容器后台模式
    4. 4.4. Docker容器使用
      1. 4.4.1. 启动已停止运行的容器
    5. 4.5. 运行一个web应用
  5. 5. Docker镜像使用
  6. 6. Docker DockerFile
  7. 7. 开始构建镜像
    1. 7.0.1. 上下文路径
  8. 7.1. Dockerfile基本结构
  9. 7.2. DockerFile关键指令
    1. 7.2.1. FROM
    2. 7.2.2. MAINTAINER
    3. 7.2.3. LABEL
    4. 7.2.4. RUN
    5. 7.2.5. CMD
    6. 7.2.6. EXPOSE
    7. 7.2.7. ENV
    8. 7.2.8. ADD
    9. 7.2.9. COPY
    10. 7.2.10. ENTRYPOINT
    11. 7.2.11. VOLUME
    12. 7.2.12. USER
    13. 7.2.13. WORKDIR
    14. 7.2.14. ONBUILD
,