Docker Compose 模板文件

简介

默认的配置文件名为 docker-compose.yml,格式为 YAML 格式。

1
2
3
4
5
6
7
version: "3"

services:
webapp:
image: examples/web
posts: "80:80"
volumes: "/data"

每个服务都必须通过 image 指定镜像或者 build 指令(需要 Dockerfile)等来自动构建生成镜像,如果使用 build 指令,在 Dockerfile 中的选项会自动获取,无需再次设置。

参数

build

指定 Dockerfile 的路径(绝对路径或相对路径)

可以使用 context 指令指定位置,dockerfile 指令指定 Dockerfile 文件名, arg 指令指定构建时的变量。

eg:

1
2
3
4
5
6
7
8
version: "3"
services:
webapp:
bulid:
context: ./div
dockerfile: Dockerfile-alternate
args:
buildno: 1

cap_add, cap_drop

指定容器的内核能力

eg: 拥有所有能力:

1
2
cap_add:
- ALL

eg: 去掉 NET_ADMIN 能力

1
2
cap_drop:
- NET_ADMIN

command

覆盖容器启动的命令

1
command: echo "hello world"

configs

cgroup_parent

指定父 cgroup 组,继承该组的资源限制。

container_name

指定容器名称,默认使用 项目名称_服务名称_序号格式。

deploy

devices

指定设备映射关系

1
2
devices:
- "/dev/ttyUSB1:/dev/ttyUSB0"

depends_on

解决容器依赖,启动先后问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '3'

services:
web:
build:
depends_on:
- db
- redis

redis:
image: redis

db:
image: mongo

dns

自定义 DNS 服务器,可以是一个值,也可以是一个列表。

1
2
3
4
5
dns: 8.8.8.8

dns:
- 8.8.8.8
- 114.114.114.114

配置 DNS 搜索域。

1
2
3
4
5
dns_search: example.com

dns_search:
- domain1.example.com
- domain2.example.com

tmpfs

挂载一个 tmpfs 文件系统到容器。

env_file

从文件中获取环境变量

环境变量格式如下:

1
PROG_ENV=development

environment

设置环境变量,可以使用数据或者字典两种格式,只给定变量名会自动获取主机上的变量值,避免数据泄漏。

1
2
3
4
5
6
7
environment:
RACK_ENV: development
SESSION_SECRET:

environment:
- RACK_ENV=development
- SESSION_SECRET

如果变量名称用到 true | false, yes | no 等表达布尔含义的值,最好放到引号里。

expose

暴露端口,但不映射到宿主机,仅可以指定内部端口为参数

不建议使用: 链接 docker-compose 外部容器,甚至非 Compose 管理的外部容器

extra_hosts

指定额外的 host 映射

1
2
3
extra_hosts:
- "googledns:8.8.8.8"
- "dockerhub:52.1.157.61"

healthcheck

检查容器是否正常

1
2
3
4
5
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3

image

指定镜像名称或ID,如果本地不存在会尝试拉取这个镜像

labels

为容器添加元数据

logging

配置日志选项

1
2
3
4
logging:
driver: syslog
options:
syslog-address: "tcp://192.168.0.42:123"

network_mode

设置网络模式

networks

配置容器链接的网络

1
2
3
4
5
6
7
8
9
10
version: "3"
services:

some-service:
networks:
- some-network
- other-network
network:
some-network:
other-network:

pid

和主机进程共享命名空间

ports

暴露端口信息,宿主机端口:容器端口,或仅指定容器端口(宿主机随机分配)

secrets

储存敏感数据,例如 mysql 密码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: "3"
services:

mysql:
image: mysql
secrets:
- db_root_password
- my_other_secret

secrets:
my_secret:
file: ./my_secret.txt
my_other_secret:
external: true

sysctls

配置容器内核参数

ulimits

指定容器大小限制

nproc: 进程数
nofile:文件句柄数(软限制和硬限制)

1
2
3
4
5
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000

volumes

数据卷所挂载路径设置

读取变量

1
2
3
4
5
version: "3"
services:

db:
image: "mongo:${MONGO_VERSION}"

MONGO_VERSION=3.2 docker-compose up, 会启动一个 mongo:3.2 镜像容器
MONGO_VERSION=2.8 docker-compose up, 会启动一个 mongo:2.8 镜像容器

评论和共享

Docker Compose 使用

定义和运行多个 Docker 容器的应用,它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML格式)来定义一组相关联的应用容器为一个项目(project)。

命令

1
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]

构建

1
docker-compose build [options] [--build-arg key=val...] [SERVICE...]

验证配置文件

验证 Compose 文件格式是否正确,正确则显示配置文件,错误显示原因

1
docker-compose config [options]

自动构建并启动服务

1
docker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]

自动尝试完成构建镜像,创建服务,启动服务,并关联服务相关容器。

链接的服务都将会被自动启动,除非已经处于运行状态。

默认 docker-compose up 启动容器在前台,Ctrl-c 会导致所有容器停止。

如果服务已经存在,docker-compose up 将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷)。

docker-compose up -d 后台启动并运行所有容器。

docker-compose up --no-recreate 启动处于停止状态的容器,忽略已经运行的。

docker-compose up --no-deps -d SERVICE 只重启部署服务

停止

停止 up 命令所启动的容器,并移除网络

1
docker-compose down [options]

进入

进入指定容器

1
docker-compose exec [options] [-e KEY=VAL...] SERVICE COMMAND [ARGS...]

列出 Compose 包含的镜像

1
docker-compose images [options] [SERVICE...]

强制停止服务容器

1
docker-compose kill [options] [SERVICE...]

查看服务器的输出

1
docker-compose logs [options] [SERVICE...]

暂停一个服务

1
docker-compose pause [SERVICE...]

恢复一个暂停的服务

1
docker-compose unpause [SERVICE...]

查看某个容器的端口

1
docker-compose port [options] SERVICE PRIVATE_PORT

列出项目中的所有容器

1
docker-compose ps [options] [SERVICE...]

拉取项目所需镜像

1
docker-compose pull [options] [SERVICE...]

推送服务依赖的镜像到 Docker 镜像仓库

1
docker-compose push [options] [SERVICE...]

重启项目中的服务

1
docker-compose restart [options] [SERVICE...]

删除所有停止状态的服务容器

1
docker-compose rm [options] [SERVICE...]

在指定服务上执行一个命令

1
docker-compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] [-l KEY=VALUE...] SERVICE [COMMAND] [ARGS...]

设置指定服务器运行的容器个数

1
docker-compose scale [options] [SERVICE=NUM...]

eg: 启动三个容器运行 web 服务,启动 2 个容器运行 db 服务

1
docker-compose scale web=3 db=2

当指定数目多于该服务实际运行容器,将创建新容器;反之将停止容器。

启动已经存在的服务容器

1
docker-compose start [SERVICE...]

停止已经运行的容器

1
docker-compose stop [options] [SERVICE...]

查看各个服务容器内运行的进程

1
docker-compose top [SERVICE...]

评论和共享

使用 Dockerfile 定制镜像

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层, 因此每一条指令的内容,就是描述该层应当如何构建。

重要概念

构建上下文

docker 的构建命令:

1
docker build [OPTIONS] PATH | URL | -

最后的参数是指上下文路径,而不是 Dockerfile 所在路径,docker 在构建的时候,会将上下文路径下的所有内容打包,然后上传给 Docker 引擎,Docker 就有权限访问上下内的文件了。

如果需要访问的文件路径超出上下文的范围,Docker 引擎就无法获得这些文件的位置,应该将这些文件复制到上下文目录中。更不应该把 Dockerfile 放到硬盘根目录去构建。如果目录中有些不希望在构建中传递给 Docker 的文件,可以放在 .dockerignore 文件夹中。

指令

FROM

指定基础镜像,必须是第一条

RUN

用于执行命令行命令的,有两种格式:

  • shell 格式:RUN <COMMAND>

  • exec 格式:RUN ["<COMMAND>", "<args1>", "<args2>", ...]

每一个 RUN 命令都会创建一层镜像,如果每一个命令都使用一个 RUN 命令,那么整个项目变得臃肿,易出错。正确写法应该如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM debian:jessie
RUN buildDeps='gcc libc6-dev make' \
&& apt-get update \
&& apt-get install -y $buildDeps \
...
# 清理为了编译构建需要的软件
&& rm -rf /var/lib/apt/lists/* \
# 清理下载文件
&& rm redis.tar.gz \
# 清理展开文件
&& rm -r /usr/src/redis \
# 清理 apt 缓存
&& apt-get purge -y --auto-remove $buildDeps

每一层构建后要清理无关文件。可以使用 docker diff 命令查看文件变化。

COPY

1
2
COPY <源路径>...<目标路径>
COPY ["<源路径>",... "<目标路径>"]

源路径可以是多个,甚至通配符,通配符要满足 Go 的 filepath.Match 规则,例如:

1
2
COPY hom* /mydir/
COPY hom?.txt /mydir/

COPY 命令会保留源文件的各种源数据属性

ADD

COPY 命令的基础上添加了自动解压的功能,推荐优先使用 COPY 命令

CMD

用于指定默认的容器主进程的启动命令,运行的时候可以指定新的命令来代替镜像设置中的这个默认命令

1
2
3
4
# shell
COPY <COMMAND>
# exec
COPY ["<COMMAND>", "<args1>", "<args2>", ...]

推荐使用 exec 格式,shell格式实际的命令会被包装为 sh -c 的参数形式执行。

1
CMD echo $HOME

解释为:

1
CMD ["sh", "-c", "echo $HOME"]

ENTRYPOINT

ENV

配置环境变量:

1
2
3
4
ENV VERSION=1.0 DEBUG=on \
NAME="Happy Feet"

RUN rm "node-v$VERSION-linux-x64.tar.xz"

ARG

和 ENV 一样,都是设置环境变量,不同的是 ARG 所设置的环境变量,在将来运行时是不会存在这些环境变量的。但不要使用 ARG 保存密码,因为 docker history 可以看到所有值。

VOLUME 定义匿名卷

1
2
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

为了保持容器存储层不发生写操作,对于数据库类需要保存动态数据的应用,为了防止运行时用户忘记挂载卷,可以先用 VOLUME 命令指定某些目录为匿名卷,防止向容器存储层写大量数据。

1
VOLUME /data

运行时:

1
docker run -d -v mydata:/data xxx

EXPOSE

声明端口

1
EXPOSE <端口1> [<端口2>]

EXPOSE 仅仅声明容器打算使用的端口,并不会自动在宿主进行端口映射。

-p 是将容器的对应端口服务公开给外界访问。

WORKDIR

指定工作目录,以后各层的当前目录就被改为指定目录。

错误示例

1
2
RUN cp /app
RUN echo "hello" > world.txt

新手容易的错误:因为构建分层存储,所以第一层 RUN cd /app 的执行仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。

USER

指定当前用户,和 WORKDIR 类似。

HEALTHCHECK

告诉 Docker 应该如何判断容器的状态是否正常,防止程序进入死循环,无法通过退出判断。

只可出现一次,多写只会生效最后一次。

ONBUILD

ONBUILD 是一个特殊的指令,后面跟其他指令,这些指令在当前镜像构建时不会执行,只有以当前镜像为基础的镜像,去构建下一级镜像的时候才会被执行。

评论和共享

Docker 基本命令

Docker 基本命令

镜像

搜索

1
docker search [OPTIONS] TERM

获取

1
docker pull [OPTIONS] NAME[:TAG|@DIGEST]

运行

1
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

常用OPTIONS:
|option|描述|
|—|—|
|-i -t|两个参数,-i 交互式操作,-t终端|
|-p|指定端口|
|-d|在后台运行容器并打印容器ID|
|--name|为容器指定名称|
|--rm|退出容器后将其删除|

挂载数据卷:

1
docker run -d -P --name web --mount source=my-vol,target=/webapp webapp python app.py

挂载主机目录:

1
docker run -d -P --name web --mount type=bind,source=/src/webapp,target=/opt/webapp,readonly webapp python app.py

列出已下载镜像

1
docker image ls [OPTIONS] [REPOSITORY[:TAG]]

删除本地镜像

1
docker image rm [OPTIONS] IMAGE [IMAGE...]

列出虚悬镜像

由于同名镜像更新产生

1
docker image ls -f dangling=true

删除虚悬镜像

1
docker image prune

占用磁盘空间

1
docker system df [OPTIONS]

查看历史

1
docker history [OPTIONS] IMAGE

推送镜像

1
docker push [OPTIONS] NAME[:TAG]

容器

启动已终止容器

1
docker container start [OPTIONS] CONTAINER [CONTAINER...]

查看日志

1
docker container logs [OPTIONS] CONTAINER

终止容器

1
docker container stop [OPTIONS] CONTAINER [CONTAINER...]

重启容器

1
docker container restart [OPTIONS] CONTAINER [CONTAINER...]

删除容器

1
docker container rm [OPTIONS] CONTAINER [CONTAINER...]

清理所有终止状态容器

1
docker container prune [OPTIONS]

进入容器

exec 命令 (推荐)

从这个 stdin 中 exit 不会导致容器停止

1
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

常用OPTIONS:
|option|描述|
|—|—|
|-i -t|两个参数,-i 交互式操作,-t终端|
|-w|容器的工作目录|
|-e|设置 ENV|

attach 命令

注意: 如果从这个 stdin 中 exit,会导致容器停止

1
docker attach [OPTIONS] CONTAINER

查看存储层变化

1
docker diff CONTAINER

提交变更

1
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

eg:

1
docker commit --author "mail@shianqi.com" --message "Change index.html" webserver nginx:v2

常用于学习,还可以在被入侵后保存现场。不要使用 docker commit 定制镜像,应该用 Dockerfile

容器和本机文件传输

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

导入导出

导出容器快照

1
docker export [OPTIONS] CONTAINER

eg:

1
docker export 329a2e380 > ubuntu.tar

导入容器

docker import

导入容器快照

1
docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

eg: 导入容器快照

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

eg: 指定url或目录导入

1
docker import http://shianqi.com/exampleimage.tgz shianqi/imagerepo

docker load

导入镜像存储文件

1
docker load [OPTIONS]

区别: 导入容器快照将丢弃所有的历史记录和元数据信息,导入镜像存储文件将保存完整记录,体积也要大。从容器快照文件中导入可以重新指定标签等信息。

数据卷

创建

1
docker volume create [OPTIONS] [VOLUME]

查看

查看所有:

1
docker volume ls [OPTIONS]

查看指定:

1
docker volume inspect [OPTIONS] VOLUME [VOLUME...]

删除

1
docker volume rm [OPTIONS] VOLUME [VOLUME...]

清理无用数据卷

1
docker volume prune [OPTIONS]

容器互联

推荐使用自定义 Docker 网络来链接多个容器,而不是使用 --link 参数

新建网络

1
docker network create [OPTIONS] NETWORK

eg:

1
docker network create -d bridge my-net

评论和共享

Docker

Docker

传统虚拟机是虚拟出一套硬件后,在其上运行一套完整的操作系统,再之上运行所需的应用进程。而容器内的应用进程直接运行于宿主机的内核,容器没有自己的内核,也没有进行硬件虚拟。因此容器比传统虚拟机更方便。

传统虚拟机:

传统虚拟机

容器:

容器

特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为MB 一般为GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

镜像

Docker 采用分层存储的架构,构建时会一层一层构建,前一层是后一层的的基础。每一层构建完就不会发生改变,后一层上的任何改变只发生在自己这一层。在构建镜像的时候要额外小心,每一层尽量只包含需要的东西,任何额外的东西应该在该层构建结束前清理掉

容器

镜像容器的关系,就像对象,镜像是静态的定义,容器是镜像运行时的实体。

容器不应该向其存储层内写入任何数据,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些 位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。

数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此,使用数据卷后,容器删除或者重新运行之后,数据却不会丢失。

评论和共享

  • 第 1 页 共 1 页
作者的图片

Archie Shi

Nothing to say


Front-End Development Engineer