细节请参考:
https://docs.docker.com/engine/reference/run/
https://docs.docker.com/compose/reference/
Github: https://github.com/docker/compose
官网:https://docs.docker.com/compose/compose-file/
1. 概述
问题:如果要使用 Docker
运行 LNMP
架构,那么 Nginx
、MySQL
、PHP
、 Linux
三个服务运行在一个容器里,还是运行在多个容器里呢?
答案是都可以。
- 你可以分别放在三个容器中
- 也可以全部放在一个容器中
- 还可以
PHP
、Linux
、Nginx
共用一个容器,MySQL
单独一个容器 - 甚至还可以分别做多个容器,实现更复杂的架构
如果实现一个容器架构(微服务架构),一个个的 docker run
启动很麻烦,更麻烦的是容器之间的连接与交互。所以我们需要用到容器编排。
2. 使用步骤
Docker Compose
将所管理的容器分为三层:
- 工程(project)
- 服务(service)
- 容器(contaienr)
Docker Compose
运行的目录下的所有文件(docker-compose.yml
、extends
文件或环境变量文件等)组成一个工程,若无特殊指定工程名即为当前目录名。
一个工程当中可包含多个服务,每个服务中定义了容器运行的镜像、参数、关系,一个服务当中可包括多个容器实例。
使用 Compose
基本上分为三步:
Dockerfile
定义应用的运行环境(镜像)docker-compose.yml
定义组成应用的各服务docker-compose up -d
构建并启动整个应用
Docker Compose
是一个由 Python
编写的软件,在拥有 Python
运行环境的机器上,我们可以直接运行它,不需要其它的操作。
3. 安装
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$
$ sudo docker-compose version
docker-compose version 1.21.2, build a133471
docker-py version: 3.3.0
CPython version: 3.6.5
OpenSSL version: OpenSSL 1.0.1t 3 May 2016
我们也能够通过 Python
的包管理工具 pip
来安装 Docker Compose
。
$ sudo pip install docker-compose
docker-compose
最早是用 Python
编写的,2.0
版本后改用 Go
语言重新实现, 1.x
的用法和 2.x
略有些不同,最后一个 Python
开发的版本是 1.29.2
。
1.x
中 docker-comose
的默认文件是 docker-compose.yml
,2.x
后默认文件也可以使用compose.yml
。
有的 docker-compose YAML
文件开头有一个 version
字段,它标记了规范的版本,用来实现向后兼容,但现在它已经被废弃了,不建议再使用。
4. 常见语法
Docker Compose
使用 Yaml
格式文件来编排。
参考: https://docs.docker.com/compose/compose-file/
与 Dockerfile
采用 Dockerfile
这个名字作为镜像构建定义的默认文件名一样,Docker Compose
的配置文件也有一个缺省的文件名,也就是 docker-compose.yml
,如非必要,我建议大家直接使用这个文件名来做 Docker Compose
项目的定义。
4.1 build
指定镜像构建时的 dockerfile
目录,格式一般为绝对路径目录或相对路径目录(dockerfile
需要命名为 Dockerfile
):
build: /path/to/build/dir
或者
build: ./dir
4.2 image
指定要启动容器的镜像:
image: redis
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd
如果镜像不存在,Compose
尝试拉它。
如果指定了构建,可以使用指定的选项构建它,并使用指定的 tag
进行标记。
4.3 environment
设置镜像变量,它可以保存变量到镜像里面,也就是说启动的容器也会包含这些变量设置。
environment
和 Dockerfile
中的 ENV
指令一样,会把变量一直保存在镜像、容器中。
格式
environment:
RACK_ENV: development
SHOW: 'true'
或
environment:
- RACK_ENV=development
- SHOW=true
4.4 expose:
这个标签与 Dockerfile
中的 EXPOSE
指令一样,用于指定暴露的端口,但只将端口暴露给连接的服务,而不暴露给主机。
expose:
- "3000"
- "8000"
4.5 ports
映射端口,可以使用 HOST:CONTAINER
的方式指定端口,也可以指定容器端口(选择临时主机端口),宿主机会随机映射端口。
ports:
- "3000"
- "3000-3005"
- "8000:8000"
- "9090-9091:8080-8081"
- "49100:22"
- "127.0.0.1:8001:8001"
- "127.0.0.1:5000-5010:5000-5010"
- "6060:6060/udp"
我们可以利用它进行宿主机与容器端口的映射,这个配置与 docker CLI
中 -p
选项的使用方法是近似的。
需要注意的是,由于 YAML
格式对 xx:yy
这种格式的解析有特殊性,在设置小于 60 的值时,会被当成时间而不是字符串来处理,所以我们最好使用引号将端口映射的定义包裹起来,避免歧义。
4.6 restart
指定 Docker
容器的重启策略。
默认值为 no
,即在任何情况下都不会重新启动容器
- 当值为
always
时,容器退出时总是重新启动(会随着 Docker 服务启动而启动容器) - 当值为
on-failure
时,当出现 on-failure 报错(非正常退出,退出状态非 0),才会重启容器 - 当值为
unless-stopped
时,在容器退出时总是重启容器,但是不考虑在 Docker 守护进程启动时就已经停止了的容器
restart: "no"
restart: always
restart: on-failure
restart: on-failure:3
restart: unless-stopped
4.7 volume
数据卷挂载,可以直接使用 HOST:CONTAINER
这样的格式,或者使用 HOST:CONTAINER:ro
这样的格式,ro
代表数据卷是只读的。
volumes:
### 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
- /var/lib/mysql
### 使用绝对路径挂载数据卷
- /opt/data:/var/lib/mysql
### 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器。
- ./cache:/tmp/cache
### 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。
- ~/configs:/etc/configs/:ro
### 已经存在的命名的数据卷。
- datavolume:/var/lib/mysql
在使用外部文件挂载的时候,我们可以直接指定相对目录进行挂载,这里的相对目录是指相对于 docker-compose.yml
文件的目录。
由于有相对目录这样的机制,我们可以将 docker-compose.yml
和所有相关的挂载文件放置到同一个文件夹下,形成一个完整的项目文件夹。这样既可以很好的整理项目文件,也利于完整的进行项目迁移。
4.8 depends_on
虽然我们在 Docker Compose
的配置文件里定义服务,在书写上有由上至下的先后关系,但实际在容器启动中,由于各种因素的存在,其顺序还是无法保障的。
所以,如果我们的服务间有非常强的依赖关系,我们就必须告知 Docker Compose
容器的先后启动顺序。只有当被依赖的容器完全启动后,Docker Compose
才会创建和启动这个容器。
此标签解决了容器的依赖、启动先后的问题。
version: '3'
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: mysql
使用 docker-compose up web
启动,会先启动 Redis
和 DB
,再启动 Web
。
在 Docker Compose
为我们启动项目的时候,会检查所有依赖,形成正确的启动顺序并按这个顺序来依次启动容器。
4.9 links
链接到其它服务的中的容器,与 link
连接一样效果,会连接到其它服务中的容器。
web:
links:
- db
- db:database
- redis
4.10 实践
version: "3"
services:
redis:
image: redis:3.2
networks:
- backend
volumes:
- ./redis/redis.conf:/etc/redis.conf:ro
ports:
- "6379:6379"
command: ["redis-server", "/etc/redis.conf"]
database:
image: mysql:5.7
networks:
- backend
volumes:
- ./mysql/my.cnf:/etc/mysql/my.cnf:ro
- mysql-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=my-secret-pw
ports:
- "3306:3306"
webapp:
build: ./webapp
networks:
- frontend
- backend
volumes:
- ./webapp:/webapp
depends_on:
- redis
- database
nginx:
image: nginx:1.12
networks:
- frontend
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./webapp/html:/webapp/html
depends_on:
- webapp
ports:
- "80:80"
- "443:443"
networks:
frontend:
backend:
volumes:
mysql-data:
在这个 Docker Compose
的示例中,我们看到占有大量篇幅的就是 services
部分,也就是服务定义的部分了。Docker Compose
中的服务,是对一组相同容器集群统一配置的定义。
在使用时,我们首先要为每个服务定义一个名称,用以区别不同的服务。在这个例子里,redis
、database
、webapp
、nginx
就是服务的名称。
在 Docker Compose
里,我们可以通过两种方式为服务指定所采用的镜像。
- 一种是通过
image
这个配置,这个相对简单,给出能在镜像仓库中找到镜像的名称即可。 - 另外一种指定镜像的方式就是直接采用
Dockerfile
来构建镜像,通过build
这个配置我们能够定义构建的环境目录,这与docker build
中的环境目录是同一个含义。如果我们通过这种方式指定镜像,那么Docker Compose
先会帮助我们执行镜像的构建,之后再通过这个镜像启动容器。
当然,在 docker build
里我们还能通过选项定义许多内容,这些在 Docker Compose
里我们依然可以。
## ......
webapp:
build:
context: ./webapp
dockerfile: webapp-dockerfile
args:
- JAVA_VERSION=1.6
## ......
由于 Docker Compose
的配置已经固化下来,所以我们不需要担心忘记之前执行了哪些命令来启动容器,当每次需要开启或关闭环境时,只需要 docker-compose up -d
和 docker-compose down
命令,就能轻松完成操作。
5. 综合案例:容器化应用部署实践
5.1 环境配置
在宿主机上打开 ip_forward
,为我们下面要映射容器的端口到宿主机,只有打开 ip_forward
才能映射成功。
### vim /etc/sysctl.conf
net.ipv4.ip_forward=1
### sysctl -p
5.2 部署 WordPress 应用
- 创建一个名为 wordpress 的 project(工程):
[root@daniel ~]### mkdir -p /docker-compose/wordpress
[root@daniel ~]### cd /docker-compose/wordpress
- 创建 docker-compose.yml:
[root@daniel wordpress]### vim docker-compose.yml
version: '3'
services:
db:
image: mysql:5.7
volumes:
- "./data:/var/lib/mysql"
restart: always
environment:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
expose:
- "3306"
wordpress:
depends_on:
- db
image: wordpress:latest
links:
- db
ports:
- "8010:80"
restart: always
environment:
WORDPRESS_DB_HOST: db:3306 # 注意这里,数据库的网络标识
WORDPRESS_DB_PASSWORD: wordpress
说明:这个应用定义了两个容器服务:db
、wordpress
。
因为 docker-compose
会自动把 db
的名字用做网络标识,所以在连接数据库的时候(字段 WORDPRESS_DB_HOST
)就不需要手动指定 IP
地址了,直接用“service”的名字 db
就行了。
db
容器通 mysql:5.7
镜像启动:
MySQL
的数据目录挂载到当前目录./data
,此目录不存在会自动创建- 容器重启策略为
always
- 设置了连接
MySQ
L 的 4 个变量
wordpress
容器通过 wordpress:latest
启动:
- 需要
db
容器先启动再启动wordpress
容器 wordpress
容器要link
连接db
容器wordpress
容器将80
端口映射到宿主机的8010
端口- 容器重启策略为
always
- 设置连接数据库的变量
- 启动:
对于开发来说,最常使用的 Docker Compose
命令就是 docker-compose up
和 docker-compose down
了。
docker-compose up
命令类似于 Docker Engine
中的 docker run
,它会根据 docker-compose.yml
中配置的内容,创建所有的容器、网络、数据卷等等内容,并将它们启动。与 docker run
一样,默认情况下 docker-compose up
会在“前台”运行,我们可以用 -d
选项使其“后台”运行。事实上,我们大多数情况都会加上 -d
选项。
[root@daniel wordpress]### docker-compose up -d
如果本地没有镜像,下载的两个镜像比较大。
[root@daniel wordpress]### docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 e9c354083de7 3 days ago 373MB
wordpress latest 4ba1e63bd20c 8 days ago 501MB
需要注意的是,docker-compose
命令默认会识别当前控制台所在目录内的 docker-compose.yml
文件,而会以这个目录的名字作为组装的应用项目的名称。如果我们需要改变它们,可以通过选项 -f
来修改识别的 Docker Compose
配置文件,通过 -p
选项来定义项目名。
docker-compose -f ./compose/docker-compose.yml -p myapp up -d
与 docker-compose up
相反,docker-compose down
命令用于停止所有的容器,并将它们删除,同时消除网络等配置内容,也就是几乎将这个 Docker Compose
项目的所有影响从 Docker
中清除。
docker-compose down
- 安装与访问
在浏览器端,访问容器主机的 8010
端口,安装访问,最终效果如下:
6. docker-compose 常用命令
在 Docker Engine
中,如果我们想要查看容器中主进程的输出内容,可以使用 docker logs
命令。而由于在 Docker Compose
下运行的服务,其命名都是由 Docker Compose
自动完成的,如果我们直接使用 docker logs
就需要先找到容器的名字,这显然有些麻烦了。我们可以直接使用 docker-compose logs
命令来完成这项工作。
$ sudo docker-compose logs nginx
在 docker-compose logs
衔接的是 Docker Compose
中所定义的服务的名称。
同理,在 Docker Compose
还有几个类似的命令可以单独控制某个或某些服务。
通过 docker-compose create
,docker-compose start
和 docker-compose stop
我们可以实现与 docker create
,docker start
和 docker stop
相似的效果,只不过操作的对象由 Docker Engine
中的容器变为了 Docker Compose
中的服务。
$ sudo docker-compose create webapp
$ sudo docker-compose start webapp
$ sudo docker-compose stop webapp
https://gitbook.cn/books/5fb91715f25ffc2d3e3d2983/index.html