Docker Compose项目介绍

Docker Compose 是 Docker 官方编排(Orchestration)项目之一,负责快速在集群中部署分布式应用。

Compose 项目目前在 Github 上进行维护。

Compose 定位是“defining and running complex applications with Docker”,前身是 Fig,兼容 Fig 的模板文件。

Dockerfile 可以让用户管理一个单独的应用容器;而 Compose 则允许用户在一个模板(YAML 格式)中定义一组相关联的应用容器(被称为一个 project ,即项目),例如一个 Web 服务容器再加上后端的数据库服务容器等。

20160716092659

该项目由 Python 编写,实际上调用了 Docker 提供的 API 来实现。

Docker Compose安装

安装 Compose 之前,要先安装 Docker,在此不再赘述。查看Docker安装教程

PIP 安装

这种方式最为推荐。

执行命令。

$ sudo pip install -U docker-compose

安装成功后,可以查看 docker-compose 命令的用法。

$ docker-compose -h
Fast, isolated development environments using Docker.
Usage:
docker-compose [options] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
--verbose                 Show more output
--version                 Print version and exit
-f, --file FILE           Specify an alternate compose file (default: docker-compose.yml)
-p, --project-name NAME   Specify an alternate project name (default: directory name)
Commands:
build   Build or rebuild services
help    Get help on a command
kill    Kill containers
logs    View output from containers
port    Print the public port for a port binding
ps      List containers
pull    Pulls service images
rm      Remove stopped containers
run     Run a one-off command
scale   Set number of containers for a service
start   Start services
stop    Stop services
restart Restart services
up      Create and start containers

之后,可以添加 bash 补全命令。

$ curl -L https://raw.githubusercontent.com/docker/compose/1.2.0/contrib/completion/bash/do

二进制包

发布的二进制包可以在 https://github.com/docker/compose/releases 找到。

下载后直接放到执行路径即可。

例如,在常见的 Linux 平台上。

$ sudo curl -L https://github.com/docker/compose/releases/download/1.2.0/docker-compose-`uname -s`-`uname $ 
sudo chmod a+x /usr/local/bin/docker-compose

Docker Compose使用

术语

首先介绍几个术语。

  • 服务(service):一个应用容器,实际上可以运行多个相同镜像的实例。
  • 项目(project):由一组关联的应用容器组成的一个完整业务单元。

可见,一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理。

场景

下面,我们创建一个经典的 Web 项目:一个 Haproxy,挂载三个 Web 容器。

创建一个 compose-haproxy-web 目录,作为项目工作目录,并在其中分别创建两个子目录: haproxy 和web 。

Web 子目录

这里用 Python 程序来提供一个简单的 HTTP 服务,打印出访问者的 IP 和 实际的本地 IP。

index.py

编写一个 index.py 作为服务器文件,代码为

#!/usr/bin/python
#authors: yeasy.github.com
#date: 2013-07-05
import sys
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import socket
import fcntl
import struct
import pickle
from datetime import datetime
from collections import OrderedDict
class HandlerClass(SimpleHTTPRequestHandler):
   def get_ip_address(self,ifname):
       s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
       return socket.inet_ntoa(fcntl.ioctl(
           s.fileno(),
           0x8915, # SIOCGIFADDR
           struct.pack('256s', ifname[:15])
       )[20:24])
   def log_message(self, format, *args):
   if len(args) < 3 or "200" not in args[1]:
      return
   try:
      request = pickle.load(open("pickle_data.txt","r"))
   except:
   request=OrderedDict()
   time_now = datetime.now()
   ts = time_now.strftime('%Y-%m-%d %H:%M:%S')
   server = self.get_ip_address('eth0')
   host=self.address_string()
   addr_pair = (host,server)
   if addr_pair not in request:
      request[addr_pair]=[1,ts]
   else:
      num = request[addr_pair][0]+1
      del request[addr_pair]
      request[addr_pair]=[num,ts]
   file=open("index.html", "w")
   file.write("<!DOCTYPE html> <html> <body><center><h1><font color=\"blue\" face=\"Georgia, Arial\" for pair in request:
     if pair[0] == host:
        guest = "LOCAL: "+pair[0]
     else:
        guest = pair[0]
     if (time_now-datetime.strptime(request[pair][1],'%Y-%m-%d %H:%M:%S')).seconds <
   file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"else:
   file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"file.write("</body> </html>");
   file.close()
   pickle.dump(request,open("pickle_data.txt","w"))
if __name__ == '__main__':
  try:
     ServerClass = BaseHTTPServer.HTTPServer
     Protocol = "HTTP/1.0"
     addr = len(sys.argv) < 2 and "0.0.0.0" or sys.argv[1]
     port = len(sys.argv) < 3 and 80 or int(sys.argv[2])
     HandlerClass.protocol_version = Protocol
     httpd = ServerClass((addr, port), HandlerClass)
     sa = httpd.socket.getsockname()
     print "Serving HTTP on", sa[0], "port", sa[1], "..."
     httpd.serve_forever()
  except:
     exit()

index.html

生成一个临时的 index.html 文件,其内容会被 index.py 更新。

$ touch index.html

Dockerfile

生成一个 Dockerfile,内容为

FROM python:2.7
WORKDIR /code
ADD . /code
EXPOSE 80
CMD python index.py

haproxy 目录

在其中生成一个 haproxy.cfg 文件,内容为

global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
listen stats :70
stats enable
stats uri /
frontend balancer
bind 0.0.0.0:80
mode http
default_backend web_backends
backend web_backends
mode http
option forwardfor
balance roundrobin
server weba weba:80 check
server webb webb:80 check
server webc webc:80 check
option httpchk GET /
http-check expect status 200

docker-compose.yml

编写 docker-compose.yml 文件,这个是 Compose 使用的主模板文件。内容十分简单,指定 3 个 web 容器,以及 1 个 haproxy 容器。

weba:
build: ./web
expose:
- 80

webb:

build: ./web
expose:
- 80
webc:
build: ./web
expose:
- 80
haproxy:
image: haproxy:latest
volumes:
- haproxy:/haproxy-override
- haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
links:
- weba
- webb
- webc
ports:
- "80:80"
- "70:70"
expose:
- "80"
- "70"

运行 compose 项目

现在 compose-haproxy-web 目录长成下面的样子。

compose-haproxy-web
├── docker-compose.yml
├── haproxy
│ └── haproxy.cfg
└── web
├── Dockerfile
├── index.html
└── index.py

在该目录下执行 docker-compose up 命令,会整合输出所有容器的输出。

$sudo docker-compose up
Recreating composehaproxyweb_webb_1...
Recreating composehaproxyweb_webc_1...
Recreating composehaproxyweb_weba_1...
Recreating composehaproxyweb_haproxy_1...
Attaching to composehaproxyweb_webb_1, composehaproxyweb_webc_1, composehaproxyweb_weba_1, composehaproxyweb

此时访问本地的 80 端口,会经过 haproxy 自动转发到后端的某个 web 容器上,刷新页面,可以观察到访问的容器地址的变化。

访问本地 70 端口,可以查看到 haproxy 的统计信息。

当然,还可以使用 consul、etcd 等实现服务发现,这样就可以避免手动指定后端的 web 容器了,更为灵活。

推荐:Docker Compose 命令说明

Docker入门教程
Docker简介 Docker基本概念 Docker安装
什么是Docker i.镜像 使用Debian操作系统安装Docker
为什么要用Docker ii.容器 使用CentOS操作系统安装Docker
iii.仓库 使用Ubuntu操作系统安装Docker
Docker images镜像详细介绍 Docker容器 Docker仓库
获取Docker images Docker容器启动 Docker Hub
查找Docker images Docker容器新建 私有仓库
下载Docker images Docker容器终止 Docker配置文件
创建我们自己的Docker images Docker容器进入容器
Docker容器导出和导入
Docker容器删除
Docker数据管理 Docker网络 Docker高级网络配置
数据卷容器 外部访问容器 快速配置指南
数据卷备份、恢复、迁移 容器互联 配置 DNS
容器访问控制
端口映射实现
配置 docker0 网桥
自定义网桥
实例:创建一个点到点连接
Docker安全 Dockerfile Docker底层实现
i. 内核名字空间 i. 基本结构 i. 基本架构
ii. 控制组 ii. 指令 ii. 名字空间
iii. 服务端防护 iii. 创建镜像 iii. 控制组
iv. 内核能力机制 iv. 联合文件系统
v. 其它安全特性 v. 容器格式
vi. 总结 网络
Docker实战案例
使用 Supervisor 来管理进程
创建 tomcat/weblogic 集群
多台物理主机之间的容器互联
标准化开发测试和生产环境
K8S中文社区微信公众号
分享到:更多 ()