Docker教程
Docker 架构
Docker 包括三个基本概念:
- 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
- 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。
Docker 容器通过 Docker 镜像来创建。容器与镜像的关系类似于面向对象编程中的对象与类。
Docker Hello World
Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在容器内运行一个应用程序。
输出Hello world
$ docker run ubuntu:15.10 /bin/echo "Hello world"
Hello world
各个参数解析:
- docker: Docker 的二进制执行文件。
- run: 与前面的 docker 组合来运行一个容器。
- ubuntu:15.10 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
- /bin/echo “Hello world”: 在启动的容器里执行的命令
以上命令完整的意思可以解释为:Docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo “Hello world”,然后输出结果。
运行交互式的容器
我们通过 docker 的两个参数 -i -t,让 docker 运行的容器实现“对话”的能力:
$ docker run -i -t ubuntu:15.10 /bin/bash
root@3a80353a6f0e:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
各个参数解析:
- -t: 在新容器内指定一个伪终端或终端。
- -i: 允许你对容器内的标准输入 (STDIN) 进行交互。
我们可以通过运行 exit 命令或者使用 CTRL+D 来退出容器。
root@3a80353a6f0e:/# exit
exit
启动容器(后台模式)
使用以下命令创建一个以进程方式运行的容器
$ docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
5ccc265dc52880570dbecc3e0d78e42813ef78d40c17befd2a3b5cb4b6aa925e
在输出中,我们没有看到期望的 “hello world”,而是一串长字符,这个长字符串叫做容器 ID,对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。
首先,我们需要确认容器有在运行,可以通过 docker ps
来查看:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5ccc265dc528 ubuntu:15.10 "/bin/sh -c 'while t…" 40 seconds ago Up 39 seconds affectionate_bohr
输出详情介绍:
CONTAINER ID: 容器 ID。
IMAGE: 使用的镜像。
COMMAND: 启动容器时运行的命令。
CREATED: 容器的创建时间。
STATUS: 容器状态。
状态有7种:
- created(已创建)
- restarting(重启中)
- running 或 Up(运行中)
- removing(迁移中)
- paused(暂停)
- exited(停止)
- dead(死亡)
PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
NAMES: 自动分配的容器名称。
在宿主主机内使用 docker logs
命令,查看容器内的标准输出:
$ docker logs 5ccc265dc528
hello world
hello world
hello world
···
$ docker logs affectionate_bohr
hello world
hello world
hello world
...
停止容器
我们使用 docker stop
命令来停止容器:
$ docker stop 5ccc265dc528
5ccc265dc528
$ docker stop affectionate_bohr
affectionate_bohr
Docker 容器使用
Docker 客户端
docker 客户端非常简单 ,我们可以直接输入 docker 命令来查看到 Docker 客户端的所有命令选项。
$ docker
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/home/john/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and
default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/home/john/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/home/john/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/home/john/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
buildx* Build with BuildKit (Docker Inc., v0.5.1-docker)
compose* Docker Compose (Docker Inc., v2.0.0-beta.6)
config Manage Docker configs
container Manage containers
context Manage contexts
image Manage images
manifest Manage Docker image manifests and manifest lists
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
scan* Docker Scan (Docker Inc., v0.8.0)
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
Run 'docker COMMAND --help' for more information on a command.
To get more help with docker, check out our guides at https://docs.docker.com/go/guides/
可以通过命令 docker command --help
更深入的了解指定的 Docker 命令使用方法。
例如我们要查看 docker stats
指令的具体使用方法:
$ docker stats --help
Usage: docker stats [OPTIONS] [CONTAINER...]
Display a live stream of container(s) resource usage statistics
Options:
-a, --all Show all containers (default shows just running)
--format string Pretty-print images using a Go template
--no-stream Disable streaming stats and only pull the first result
--no-trunc Do not truncate output
容器使用
获取镜像
如果我们本地没有 ubuntu 镜像,我们可以使用 docker pull 命令来载入 ubuntu 镜像:
$ docker pull ubuntu
启动容器
以下命令使用 ubuntu 镜像启动一个容器,参数为以命令行模式进入该容器:
$ docker run -it ubuntu /bin/bash
参数说明:
- -i: 交互式操作。
- -t: 终端。
- ubuntu: ubuntu 镜像。
- /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
要退出终端,直接输入 exit
:
john@LAPTOP-VKE4F570:~$ docker run -it ubuntu /bin/bash
root@600f69d4c45b:/#
启动已停止运行的容器
查看所有的容器命令如下:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
600f69d4c45b ubuntu "/bin/bash" 28 seconds ago Exited (0) 5 seconds ago practical_morse
使用 docker start 启动一个已停止的容器:
$ docker start 600f69d4c45b
600f69d4c45b
后台运行
在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d
指定容器的运行模式。
$ docker run -itd --name ubuntu-test ubuntu /bin/bash
a5bdd7c91268b426963c6977078aa33d8346356e73421e81f0d199d312703071
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a5bdd7c91268 ubuntu "/bin/bash" 6 seconds ago Up 5 seconds ubuntu-test
注:加了 -d
参数默认不会进入容器,想要进入容器需要使用指令 docker exec
停止一个容器
停止容器的命令如下:
$ docker stop 600f69d4c45b
600f69d4c45b
停止的容器可以通过 docker restart 重启:
$ docker restart 600f69d4c45b
600f69d4c45b
进入容器
在使用 -d
参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
docker attach
$ docker attach 600f69d4c45b
root@600f69d4c45b:/# exit
exit
注意: 如果从这个容器退出,会导致容器的停止。
docker exec
:推荐大家使用docker exec
命令,因为此退出容器终端,不会导致容器的停止。
$ docker exec -it a5bdd7c91268 /bin/bash
root@a5bdd7c91268:/# exit
exit
注意: 如果从这个容器退出,容器不会停止,这就是为什么推荐大家使用 docker exec
的原因。
更多参数说明请使用 docker exec --help
命令查看。
导出和导入容器
- 导出容器
如果要导出本地某个容器,可以使用 docker export
命令。
$ docker export 1e560fca3906 > ubuntu.tar
导出容器 1e560fca3906 快照到本地文件 ubuntu.tar。
$ docker export a5bdd7c91268 > ubuntu.tar
$ ls -ll
total 73404
-rw-rw-r-- 1 john john 75158528 Nov 1 15:50 ubuntu.tar
这样将导出容器快照到本地文件。
- 导入容器快照
可以使用 docker import
从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1
$ cat ubuntu.tar | docker import - test/ubuntu:v1
sha256:359d5408c2f4f63052d06e3350da72e58673444c7f486e8f10f9c51fa01685db
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/ubuntu v1 359d5408c2f4 9 seconds ago 72.8MB
此外,也可以通过指定 URL 或者某个目录来导入,例如:
$ docker import http://example.com/exampleimage.tgz example/imagerepo
删除容器
删除容器使用 docker rm
命令:
$ docker rm -f a5bdd7c91268
a5bdd7c91268
下面的命令可以清理掉所有处于终止状态的容器。
~$ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
600f69d4c45bccf469ac8b802c44453996b3fe368ecdad3bb914fa85af532db9
34b47c53cabe27cb49b5c2531067b6e0d3c41e061b43711bba4c467aa21f8813
5ccc265dc52880570dbecc3e0d78e42813ef78d40c17befd2a3b5cb4b6aa925e
3a80353a6f0eb1d35537867186165897176eb6d9fef4bdf40480200f24fe3bb1
4529d6a2e25cc7acf38f89b4aad13771221fa909d53d7c5543d6a26c9ce88bd8
Total reclaimed space: 16B
运行一个 web 应用
前面我们运行的容器并没有一些什么特别的用处。
接下来让我们尝试使用 docker 构建一个 web 应用程序。
我们将在docker容器中运行一个 Python Flask 应用来运行一个web应用。
$ docker run -d -P training/webapp python app.py
322facb2de01ef2cab0d43573a670478b95b6fa59334687a338be9c859963619
参数说明:
-d
:让容器在后台运行。-P
:将容器内部使用的网络端口随机映射到我们使用的主机上。
查看 WEB 应用容器
使用 docker ps
来查看我们正在运行的容器:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
322facb2de01 training/webapp "python app.py" 16 seconds ago Up 15 seconds 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp beautiful_montalcini
这里多了端口信息,Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 49153上。
这时我们可以通过浏览器访问WEB应用,我们也可以通过 -p 参数来设置不一样的端口:
$ docker run -d -p 5000:5000 training/webapp python app.py
afa7a98b527fe2279a161fb8ddac83436b97686d1586e309a6eee6a970e99aa4
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
afa7a98b527f training/webapp "python app.py" 17 seconds ago Up 16 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp agitated_moore
322facb2de01 training/webapp "python app.py" 56 seconds ago Up 55 seconds 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp beautiful_montalcini
容器内部的 5000 端口映射到我们本地主机的 5000 端口上。
网络端口的快捷方式
通过 docker ps
命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port
,使用 docker port
可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。
上面我们创建的 web 应用容器 ID 为 afa7a98b527f 名字为 agitated_moore。
我可以使用 docker port afa7a98b527f 或 docker port agitated_moore 来查看容器端口的映射情况。
$ docker port afa7a98b527f
5000/tcp -> 0.0.0.0:5000
5000/tcp -> :::5000
$ docker port agitated_moore
5000/tcp -> 0.0.0.0:5000
5000/tcp -> :::5000
查看 WEB 应用程序日志
docker logs [ID或者名字]
可以查看容器内部的标准输出。
$ docker logs -f afa7a98b527f
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
172.17.0.1 - - [01/Nov/2021 08:03:22] "GET / HTTP/1.1" 200 -
172.17.0.1 - - [01/Nov/2021 08:03:22] "GET /favicon.ico HTTP/1.1" 404 -
-f: 让 docker logs
像使用 tail -f
一样来输出容器内部的标准输出。
从上面,我们可以看到应用程序使用的是 5000 端口并且能够查看到应用程序的访问日志。
查看WEB应用程序容器的进程
我们还可以使用 docker top
来查看容器内部运行的进程
$ docker top afa7a98b527f
UID PID PPID C STIME TTY TIME CMD
root 4393 4372 0 08:03 ? 00:00:00 python app.py
检查 WEB 应用程序
使用 docker inspect
来查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。
$ docker inspect afa7a98b527f
[
{
"Id": "afa7a98b527fe2279a161fb8ddac83436b97686d1586e309a6eee6a970e99aa4",
"Created": "2021-11-01T08:03:08.4229853Z",
"Path": "python",
"Args": [
"app.py"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 4393,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-11-01T08:03:08.9028728Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
......
Docker 镜像使用
当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。
列出镜像列表
我们可以使用 docker images
来列出本地主机上的镜像。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ba6acccedd29 2 weeks ago 72.8MB
docker/getting-started latest 021a1b85e641 10 months ago 27.6MB
redis 5.0.5 63130206b0fa 2 years ago 98.2MB
ju5ton1y/redis latest 21853cdd9894 2 years ago 367MB
infoslack/dvwa latest 779975a3607d 4 years ago 465MB
ubuntu 15.10 9b9cb95443b5 5 years ago 137MB
training/webapp latest 6fae60ef3446 6 years ago 349MB
各个选项说明:
- REPOSITORY:表示镜像的仓库源
- TAG:镜像的标签
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.10、14.04 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
所以,我们如果要使用版本为15.10的ubuntu系统镜像来运行容器时,命令如下:
$ docker run -t -i ubuntu:15.10 /bin/bash
如果要使用版本为 14.04 的 ubuntu 系统镜像来运行容器时,命令如下:
$ docker run -t -i ubuntu:14.04 /bin/bash
如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。
获取一个新的镜像
当我们在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果我们想预先下载这个镜像,我们可以使用 docker pull 命令来下载它。
$ docker pull ubuntu:15.10
15.10: Pulling from library/ubuntu
7dcf5a444392: Pull complete
759aa75f3cee: Pull complete
3fa871dc8a2b: Pull complete
224c42ae46e7: Pull complete
Digest: sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3
Status: Downloaded newer image for ubuntu:15.10
docker.io/library/ubuntu:15.10
下载完成后,我们可以直接使用这个镜像来运行容器。
查找镜像
我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为:Docker Hub
我们也可以使用 docker search
命令来搜索镜像。比如我们需要一个 httpd 的镜像来作为我们的 web 服务。我们可以通过 docker search
命令搜索 httpd 来寻找适合我们的镜像。
$ docker search httpd
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
httpd The Apache HTTP Server Project 3746 [OK]
centos/httpd-24-centos7 Platform for running Apache httpd 2.4 or bui… 40
centos/httpd 34 [OK]
arm32v7/httpd The Apache HTTP Server Project 10
polinux/httpd-php Apache with PHP in Docker (Supervisor, CentO… 5 [OK]
NAME: 镜像仓库源的名称
DESCRIPTION: 镜像的描述
OFFICIAL: 是否 docker 官方发布
stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。
AUTOMATED: 自动构建。
删除镜像
镜像删除使用 docker rmi 命令,比如我们删除 hello-world 镜像:
$ docker rmi ubuntu:15.10
Untagged: ubuntu:15.10
Untagged: ubuntu@sha256:02521a2d079595241c6793b2044f02eecf294034f31d6e235ac4b2b54ffc41f3
Deleted: sha256:9b9cb95443b5f846cd3c8cfa3f64e63b6ba68de2618a08875a119c81a8f96698
Deleted: sha256:b616585738eaf78ff7d86c7526caf7c91a35bc4028ef63204e5bfee82f7494b5
Deleted: sha256:dee1316f97acc7e1a5088b02fbc2b3078e0bfa038dd904b8072e2de5656e7bb8
Deleted: sha256:e7d9ae1a69c53c9fefa1aef34348be5a5dbf2fe79e7dd647b3d4f4e927587ebc
Deleted: sha256:f121afdbbd5dd49d4a88c402b1a1a4dca39c9ae75ed7f80a29ffd9739fc680a7
创建镜像
当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。
- 从已经创建的容器中更新镜像,并且提交这个镜像
- 使用 Dockerfile 指令来创建一个新的镜像
更新镜像
更新镜像之前,我们需要使用镜像来创建一个容器。
docker run -t -i ubuntu /bin/bash
在运行的容器内使用 apt-get update
命令进行更新。
在完成操作之后,输入 exit
命令来退出这个容器。
此时 ID 为 d7539653fa1a 的容器,是按我们的需求更改的容器。我们可以通过命令 docker commit
来提交容器副本。
$ docker commit -m="has update" -a="john" d7539653fa1a john/ubuntu:v2
sha256:d5824c4282e0ce513e70c70e1e3e9fbced74380472594edace2c6e3e52f8b029
各个参数说明:
- -m: 提交的描述信息
- -a: 指定镜像作者
- e218edb10161:容器 ID
- runoob/ubuntu:v2: 指定要创建的目标镜像名
我们可以使用 docker images
命令来查看我们的新镜像 runoob/ubuntu:v2:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
john/ubuntu v2 d5824c4282e0 2 minutes ago 104MB
构建镜像
我们使用命令 docker build
, 从零开始来创建一个新的镜像。为此,我们需要创建一个 Dockerfile 文件,其中包含一组指令来告诉 Docker 如何构建我们的镜像。
$ cat Dockerfile
FROM ubuntu
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
每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。
第一条FROM
,指定使用哪个镜像源
RUN
指令告诉 docker 在镜像内执行命令,安装了什么。
然后,我们使用 Dockerfile 文件,通过 docker build
命令来构建一个镜像。
$ docker build -t john/centos:6.7 .
参数说明:
-t
:指定要创建的目标镜像名.
:Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径
使用 docker images
查看创建的镜像已经在列表中存在,镜像ID为 e0e1afe3142a
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
john/ubuntu latest e0e1afe3142a 25 seconds ago 73.1MB
设置镜像标签
我们可以使用 docker tag
命令,为镜像添加一个新的标签。
$ docker tag e0e1afe3142a john/ubuntu:test
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
john/ubuntu latest e0e1afe3142a 3 hours ago 73.1MB
john/ubuntu test e0e1afe3142a 3 hours ago 73.1MB
docker tag [镜像ID]
,这里是 e0e1afe3142a,用户名称、镜像源名(repository name)和新的标签名(tag)。
使用 docker images
命令可以看到,ID为e0e1afe3142a的镜像多一个标签。
Docker 容器连接
前面我们实现了通过网络端口来访问运行在 docker 容器内的服务。
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P
或 -p
参数来指定端口映射。
网络端口映射
我们创建了一个 python 应用的容器。
$ docker run -d -P training/webapp python app.py
另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。
我们使用 -P
绑定端口号,使用 docker ps
可以看到容器端口 5000 绑定主机端口 49154。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e3ea25d48072 training/webapp "python app.py" 25 seconds ago Up 24 seconds 0.0.0.0:49154->5000/tcp, :::49154->5000/tcp adoring_wescoff
我们也可以使用 -p
标识来指定容器端口绑定到主机端口。
两种方式的区别是:
-P
:是容器内部端口随机映射到主机的高端口。-p
: 是容器内部端口绑定到指定的主机端口。
$ docker run -d -p 5000:5000 training/webapp python app.py
76c2243171c31d1643d2fcb806da8e878513e1f8245daea88dfffabe287071a9
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76c2243171c3 training/webapp "python app.py" 6 seconds ago Up 3 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp sweet_solomon
e3ea25d48072 training/webapp "python app.py" 3 minutes ago Up 3 minutes 0.0.0.0:49154->5000/tcp, :::49154->5000/tcp adoring_wescoff
另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。
$ docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
f74ec8fcc29d8e9aa7df0362a6884e7472afa70b441ec8b22358ce10d2b61151
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f74ec8fcc29d training/webapp "python app.py" 4 seconds ago Up 3 seconds 127.0.0.1:5001->5000/tcp sweet_lederberg
76c2243171c3 training/webapp "python app.py" 5 minutes ago Up 5 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp sweet_solomon
e3ea25d48072 training/webapp "python app.py" 9 minutes ago Up 9 minutes 0.0.0.0:49154->5000/tcp, :::49154->5000/tcp adoring_wescoff
如果要绑定 UDP 端口,可以在端口后面加上 /udp
。
$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
13219cddc5c18d3d444c6e3b6673becebef7d8225f4c1666bdb9d46c2562119a
john@LAPTOP-VKE4F570:~/docker$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
13219cddc5c1 training/webapp "python app.py" 5 seconds ago Up 3 seconds 5000/tcp, 127.0.0.1:5000->5000/udp agitated_archimedes
f74ec8fcc29d training/webapp "python app.py" 2 minutes ago Up 2 minutes 127.0.0.1:5001->5000/tcp sweet_lederberg
76c2243171c3 training/webapp "python app.py" 8 minutes ago Up 8 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp sweet_solomon
e3ea25d48072 training/webapp "python app.py" 12 minutes ago Up 12 minutes 0.0.0.0:49154->5000/tcp, :::49154->5000/tcp adoring_wescoff
docker port
命令可以让我们快捷地查看端口的绑定情况。
$ docker port sweet_lederberg
5000/tcp -> 127.0.0.1:5001
Docker 容器互联
端口映射并不是唯一把 docker 连接到另一个容器的方法。
docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。
docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。
容器命名
当我们创建一个容器的时候,docker 会自动对它进行命名。另外,我们也可以使用 --name
标识来命名容器,例如:
$ docker run -d -P --name John training/webapp python app.py
5029fcdb090b657e976dc22959a4d8b23872f724fba7885267b3ce2eb48bb660
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5029fcdb090b training/webapp "python app.py" 3 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp, :::49155->5000/tcp John
我们可以使用 docker ps
命令来查看容器名称。
新建网络
下面先创建一个新的 Docker 网络。
$ docker network create -d bridge test-net
4e046933732baf4d4f47ab79fd2f3ffde705545c21bb90f2094ca26680ac9854
参数说明:
-d:参数指定 Docker 网络类型,有 bridge、overlay。其中 overlay 网络类型用于 Swarm mode。
连接容器
运行一个容器并连接到新建的 test-net 网络:
$ docker run -itd --name test1 --network test-net ubuntu /bin/bash
5a97318b617032c7a2056c8a19088dc7b7da6d2f126bbdd9adbf05a18a537a26
打开新的终端,再运行一个容器并加入到 test-net 网络:
$ docker run -itd --name test2 --network test-net ubuntu /bin/bash
f708bdb6b7856766537a41e1c93772e766aed624ddd23c8002dfd6e85554eef7
下面通过 ping 来证明 test1 容器和 test2 容器建立了互联关系。
如果 test1、test2 容器内中无 ping 命令,则在容器内执行以下命令安装 ping
$ apt-get update
$ apt install iputils-ping
在 test1 容器输入以下命令:
root@5a97318b6170:/# ping test2
PING test2 (172.19.0.3) 56(84) bytes of data.
64 bytes from test2.test-net (172.19.0.3): icmp_seq=1 ttl=64 time=0.537 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=2 ttl=64 time=0.102 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=3 ttl=64 time=0.114 ms
64 bytes from test2.test-net (172.19.0.3): icmp_seq=4 ttl=64 time=0.102 ms
^C
--- test2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3045ms
rtt min/avg/max/mdev = 0.102/0.213/0.537/0.186 ms
在 test2 容器上也同理,这样,test1 容器和 test2 容器建立了互联关系。
如果你有多个容器之间需要互相连接,推荐使用 Docker Compose。
配置 DNS
我们可以在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置全部容器的 DNS:
{
"dns" : [
"114.114.114.114",
"8.8.8.8"
]
}
设置后,启动容器的 DNS 会自动配置为 114.114.114.114 和 8.8.8.8。
配置完,需要重启 docker 才能生效。
查看容器的 DNS 是否生效可以使用以下命令,它会输出容器的 DNS 信息:
$ docker run -it --rm ubuntu cat etc/resolv.conf
# DNS requests are forwarded to the host. DHCP DNS options are ignored.
nameserver 192.168.65.5
手动指定容器的配置
如果只想在指定的容器设置 DNS,则可以使用以下命令:
$ docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
root@host_ubuntu:/# cat /etc/hostname
host_ubuntu
root@host_ubuntu:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 host_ubuntu
root@host_ubuntu:/# cat /etc/resolv.conf
search test.com
nameserver 114.114.114.114
参数说明:
--rm
:容器退出时自动清理容器内部的文件系统。
-h HOSTNAME
或者 --hostname=HOSTNAME
: 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts。
--dns=IP_ADDRESS
: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。
--dns-search=DOMAIN
: 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com。
如果在容器启动时没有指定 --dns
和 --dns-search
,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS。
Docker 仓库管理
仓库(Repository)是集中存放镜像的地方。
Docker Hub
目前 Docker 官方维护了一个公共仓库 Docker Hub。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
注册
在 https://hub.docker.com 免费注册一个 Docker 账号。
登录和退出
登录需要输入用户名和密码,登录成功后,我们就可以从 docker hub 上拉取自己账号下的全部镜像。
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: jjohn1frod
Password:
Login Succeeded
退出 docker hub 可以使用以下命令:
$ docker logout
Removing login credentials for https://index.docker.io/v1/
拉取镜像
你可以通过 docker search 命令来查找官方仓库中的镜像,并利用 docker pull 命令来将它下载到本地。
以 ubuntu 为关键词进行搜索:
$ docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 13050 [OK]
dorowu/ubuntu-desktop-lxde-vnc Docker image to provide HTML5 VNC interface … 584 [OK]
websphere-liberty WebSphere Liberty multi-architecture images … 281 [OK]
rastasheep/ubuntu-sshd Dockerized SSH service, built on top of offi… 256 [OK]
consol/ubuntu-xfce-vnc Ubuntu container with "headless" VNC session… 243 [OK]
......
使用 docker pull 将官方 ubuntu 镜像下载到本地:
$ docker pull ubuntu
Using default tag: lastest
latest: Pulling from library/ubuntu
7b1a6ab2e44d: Pull complete
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:latest
推送镜像
用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub。
以下命令中的 username 请替换为你的 Docker 账号用户名。
$ docker tag ubuntu:18.04 username/ubuntu:18.04
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED ...
ubuntu 18.04 275d79972a86 6 days ago ...
username/ubuntu 18.04 275d79972a86 6 days ago ...
$ docker push username/ubuntu:18.04
$ docker search username/ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
username/ubuntu
Docker Dockerfile
什么是 Dockerfile?
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
使用 Dockerfile 定制镜像
这里仅讲解如何运行 Dockerfile 文件来定制一个镜像,具体 Dockerfile 文件内指令详解,将在下一节中介绍,这里你只要知道构建的流程即可。
1、下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)
在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
2、FROM 和 RUN 指令的作用
FROM
:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
RUN
:用于执行后面跟着的命令行命令。有以下俩种格式:
shell 格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum -y 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 -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 &&
符号连接命令,这样执行后,只会创建 1 层镜像。
开始构建镜像
在 Dockerfile 文件的存放目录下,执行构建动作。
以下示例,通过目录下的 Dockerfile 构建一个 nginx:v3(镜像名称:镜像标签)。
注:最后的 . 代表本次执行的上下文路径
$ docker build -t nginx:v3 .
[+] Building 0.3s (4/5)
[+] Building 0.4s (4/5)
[+] Building 0.5s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 139B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/nginx:latest 0.0s
=> [1/2] FROM docker.io/library/nginx 0.1s
=> [2/2] RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html 0.2s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:24c20d9577c016867a20a84ee0ce090d298f6e9e85fee30a5a61eb006bdc36bd 0.0s
=> => naming to docker.io/library/nginx:v3 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v3 24c20d9577c0 41 seconds ago 133MB
上下文路径
上一节中,有提到指令最后一个 . 是上下文路径,那么什么是上下文路径呢?
$ docker build -t nginx:v3 .
上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build
命令得知这个路径后,会将路径下的所有内容打包。
解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
指令详解
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
ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在
docker run
时运行。 - RUN 是在
docker build
。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run
命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
ENTRYPOINT
类似于 CMD
指令,但其不会被 docker run
的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT
指令指定的程序。
但是, 如果运行 docker run
时使用了 --entrypoint
选项,将覆盖 CMD
指令指定的程序。
优点:在执行 docker run
的时候可以指定 ENTRYPOINT
运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT
指令,仅最后一个生效。
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
可以搭配 CMD 命令使用:一般是变参才会使用 CMD
,这里的 CMD
等于是在给 ENTRYPOINT
传参
example:
假设已通过 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 <其它指令>
LABEL
LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
比如我们可以添加镜像的作者:
LABEL org.opencontainers.image.authors="runoob"
Docker Compose
Compose 简介
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
- 使用 Dockerfile 定义应用程序的环境。
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
docker-compose.yml 的配置案例如下(配置参数参考下文):
# yaml 配置实例
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
使用
1、准备
创建一个测试目录,在测试目录中创建一个名为 app.py 的文件,并复制粘贴以下内容:
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
在此示例中,redis 是应用程序网络上的 redis 容器的主机名,该主机使用的端口为 6379。
在 composetest 目录中创建另一个名为 requirements.txt 的文件,内容如下:
flask
redis
2、创建 Dockerfile 文件
在 composetest 目录中,创建一个名为 Dockerfile 的文件,内容如下:
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["flask", "run"]
Dockerfile 内容解释:
- FROM python:3.7-alpine: 从 Python 3.7 映像开始构建镜像。
- WORKDIR /code: 将工作目录设置为 /code。
- “`dockerfile
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
设置 flask 命令使用的环境变量。
- **RUN apk add --no-cache gcc musl-dev linux-headers**: 安装 gcc,以便诸如 MarkupSafe 和 SQLAlchemy 之类的 Python 包可以编译加速。
- ```dockerfile
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
复制 requirements.txt 并安装 Python 依赖项。
- COPY . .: 将 . 项目中的当前目录复制到 . 镜像中的工作目录。
- CMD [“flask”, “run”]: 容器提供默认的执行命令为:flask run。
3、创建 docker-compose.yml
在测试目录中创建一个名为 docker-compose.yml 的文件,然后粘贴以下内容:
# yaml 配置
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
该 Compose 文件定义了两个服务:web 和 redis。
- web:该 web 服务使用从 Dockerfile 当前目录中构建的镜像。然后,它将容器和主机绑定到暴露的端口 5000。此示例服务使用 Flask Web 服务器的默认端口 5000 。
- redis:该 redis 服务使用 Docker Hub 的公共 Redis 映像。
4、使用 Compose 命令构建和运行您的应用
在测试目录中,执行以下命令来启动应用程序:
$ docker-compose up
如果你想在后台执行该服务可以加上 -d
参数:
$ docker-compose up -d
yml 配置指令参考
version
指定本 yml 依从的 compose 哪个版本制定的。
build
指定为构建镜像上下文路径:
例如 webapp 服务,指定为从上下文路径 ./dir/Dockerfile 所构建的镜像:
version: "3.7"
services:
webapp:
build: ./dir
或者,作为具有在上下文指定的路径的对象,以及可选的 Dockerfile 和 args:
version: "3.7"
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
labels:
- "com.example.description=Accounting webapp"
- "com.example.department=Finance"
- "com.example.label-with-empty-value"
target: prod
- context:上下文路径。
- dockerfile:指定构建镜像的 Dockerfile 文件名。
- args:添加构建参数,这是只能在构建过程中访问的环境变量。
- labels:设置构建镜像的标签。
- target:多层构建,可以指定构建哪一层。
cap_add,cap_drop
添加或删除容器拥有的宿主机的内核功能。
cap_add:
- ALL # 开启全部权限
cap_drop:
- SYS_PTRACE # 关闭 ptrace权限
cgroup_parent
为容器指定父 cgroup 组,意味着将继承该组的资源限制。
cgroup_parent: m-executor-abcd
command
覆盖容器启动的默认命令。
command: ["bundle", "exec", "thin", "-p", "3000"]
container_name
指定自定义容器名称,而不是生成的默认名称。
container_name: my-web-container
depends_on
设置依赖关系。
- docker-compose up :以依赖性顺序启动服务。在以下示例中,先启动 db 和 redis ,才会启动 web。
- docker-compose up SERVICE :自动包含 SERVICE 的依赖项。在以下示例中,docker-compose up web 还将创建并启动 db 和 redis。
- docker-compose stop :按依赖关系顺序停止服务。在以下示例中,web 在 db 和 redis 之前停止。
version: "3.7"
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
注意:web 服务不会等待 redis db 完全启动 之后才启动。
deploy
指定与服务的部署和运行有关的配置。只在 swarm 模式下才会有用。
version: "3.7"
services:
redis:
image: redis:alpine
deploy:
mode:replicated
replicas: 6
endpoint_mode: dnsrr
labels:
description: "This redis service label"
resources:
limits:
cpus: '0.50'
memory: 50M
reservations:
cpus: '0.25'
memory: 20M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
可以选参数:
endpoint_mode:访问集群服务的方式。
endpoint_mode: vip
# Docker 集群服务一个对外的虚拟 ip。所有的请求都会通过这个虚拟 ip 到达集群服务内部的机器。
endpoint_mode: dnsrr
# DNS 轮询(DNSRR)。所有的请求会自动轮询获取到集群 ip 列表中的一个 ip 地址。
labels:在服务上设置标签。可以用容器上的 labels(跟 deploy 同级的配置) 覆盖 deploy 下的 labels。
mode:指定服务提供的模式。
- replicated:复制服务,复制指定服务到集群的机器上。
- global:全局服务,服务将部署至集群的每个节点。
- 图解:下图中黄色的方块是 replicated 模式的运行情况,灰色方块是 global 模式的运行情况。
replicas:mode 为 replicated 时,需要使用此参数配置具体运行的节点数量。
resources:配置服务器资源使用的限制,例如上例子,配置 redis 集群运行需要的 cpu 的百分比 和 内存的占用。避免占用资源过高出现异常。
restart_policy:配置如何在退出容器时重新启动容器。
- condition:可选 none,on-failure 或者 any(默认值:any)。
- delay:设置多久之后重启(默认值:0)。
- max_attempts:尝试重新启动容器的次数,超出次数,则不再尝试(默认值:一直重试)。
- window:设置容器重启超时时间(默认值:0)。
rollback_config:配置在更新失败的情况下应如何回滚服务。
- parallelism:一次要回滚的容器数。如果设置为0,则所有容器将同时回滚。
- delay:每个容器组回滚之间等待的时间(默认为0s)。
- failure_action:如果回滚失败,该怎么办。其中一个 continue 或者 pause(默认pause)。
- monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
- max_failure_ratio:在回滚期间可以容忍的故障率(默认为0)。
- order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认 stop-first )。
update_config:配置应如何更新服务,对于配置滚动更新很有用。
- parallelism:一次更新的容器数。
- delay:在更新一组容器之间等待的时间。
- failure_action:如果更新失败,该怎么办。其中一个 continue,rollback 或者pause (默认:pause)。
- monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
- max_failure_ratio:在更新过程中可以容忍的故障率。
- order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认stop-first)。
注:仅支持 V3.4 及更高版本。
devices
指定设备映射列表。
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"
dns
自定义 DNS 服务器,可以是单个值或列表的多个值。
dns: 8.8.8.8
dns:
- 8.8.8.8
- 9.9.9.9
dns_search
自定义 DNS 搜索域。可以是单个值或列表。
dns_search: example.com
dns_search:
- dc1.example.com
- dc2.example.com
entrypoint
覆盖容器默认的 entrypoint。
entrypoint: /code/entrypoint.sh
也可以是以下格式:
entrypoint:
- php
- -d
- zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
- -d
- memory_limit=-1
- vendor/bin/phpunit
env_file
从文件添加环境变量。可以是单个值或列表的多个值。
env_file: .env
也可以是列表格式:
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env
environment
添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。
environment:
RACK_ENV: development
SHOW: 'true'
expose
暴露端口,但不映射到宿主机,只被连接的服务访问。
仅可以指定内部端口为参数:
expose:
- "3000"
- "8000"
extra_hosts
添加主机名映射。类似 docker client –add-host。
extra_hosts:
- "somehost:162.242.195.82"
- "otherhost:50.31.209.229"
以上会在此服务的内部容器中 /etc/hosts 创建一个具有 ip 地址和主机名的映射关系:
162.242.195.82 somehost
50.31.209.229 otherhost
healthcheck
用于检测 docker 服务是否健康运行。
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] # 设置检测程序
interval: 1m30s # 设置检测间隔
timeout: 10s # 设置检测超时时间
retries: 3 # 设置重试次数
start_period: 40s # 启动后,多少秒开始启动检测程序
image
指定容器运行的镜像。以下格式都可以:
image: redis
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd # 镜像id
logging
服务的日志记录配置。
driver:指定服务容器的日志记录驱动程序,默认值为json-file。有以下三个选项
driver: "json-file"
driver: "syslog"
driver: "none"
仅在 json-file 驱动程序下,可以使用以下参数,限制日志得数量和大小。
logging:
driver: json-file
options:
max-size: "200k" # 单个文件大小为200k
max-file: "10" # 最多10个文件
当达到文件限制上限,会自动删除旧得文件。
syslog 驱动程序下,可以使用 syslog-address 指定日志接收地址。
logging:
driver: syslog
options:
syslog-address: "tcp://192.168.0.42:123"
network_mode
设置网络模式。
network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
networks
配置容器连接的网络,引用顶级 networks 下的条目 。
services:
some-service:
networks:
some-network:
aliases:
- alias1
other-network:
aliases:
- alias2
networks:
some-network:
# Use a custom driver
driver: custom-driver-1
other-network:
# Use a custom driver which takes special options
driver: custom-driver-2
aliases :同一网络上的其他容器可以使用服务名称或此别名来连接到对应容器的服务。
restart
- no:是默认的重启策略,在任何情况下都不会重启容器。
- always:容器总是重新启动。
- on-failure:在容器非正常退出时(退出状态非0),才会重启容器。
- unless-stopped:在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
restart: "no"
restart: always
restart: on-failure
restart: unless-stopped
注:swarm 集群模式,请改用 restart_policy。
secrets
存储敏感数据,例如密码:
version: "3.1"
services:
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my_secret
secrets:
- my_secret
secrets:
my_secret:
file: ./my_secret.txt
security_opt
修改容器默认的 schema 标签。
security-opt:
- label:user:USER # 设置容器的用户标签
- label:role:ROLE # 设置容器的角色标签
- label:type:TYPE # 设置容器的安全策略标签
- label:level:LEVEL # 设置容器的安全等级标签
stop_grace_period
指定在容器无法处理 SIGTERM (或者任何 stop_signal 的信号),等待多久后发送 SIGKILL 信号关闭容器。
stop_grace_period: 1s # 等待 1 秒
stop_grace_period: 1m30s # 等待 1 分 30 秒
默认的等待时间是 10 秒。
stop_signal
设置停止容器的替代信号。默认情况下使用 SIGTERM 。
以下示例,使用 SIGUSR1 替代信号 SIGTERM 来停止容器。
stop_signal: SIGUSR1
sysctls
设置容器中的内核参数,可以使用数组或字典格式。
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0
tmpfs
在容器内安装一个临时文件系统。可以是单个值或列表的多个值。
tmpfs: /run
tmpfs:
- /run
- /tmp
ulimits
覆盖容器默认的 ulimit。
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
volumes
将主机的数据卷或着文件挂载到容器里。
version: "3.7"
services:
db:
image: postgres:latest
volumes:
- "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
- "/localhost/data:/var/lib/postgresql/data"