一文掌握Docker Compose
文章目录
[隐藏]
- 一、Docker Compose介绍
- 二、Docker Compose安装
- 三、Docker Compose基本示例
- 1、基本文件及目录设置
- 2、创建一个Dockerfile
- 3、通过docker-compose.yml定义服务
- 4、通过Docker Compose构建并启动服务
- 5、修改Compse文件,添加一个挂载点
- 6、 更新应用
- 四、Docker Compose常用命令说明
- 五、Docker Compose文件详解
- 1、version
- 2、services
- 3、networks
- 4、volumes
- 六、Docker Compose案例实践
- 1、部署一个web集群
- 2、使用Docker Compose一键部署zabbix
一、Docker Compose介绍
Docker Compose是一个定义和运行多容器应用的单机编排工具。通过Docker Compose你可以使用一个单一的YAML文件来配置多个应用服务,通过一条命令,就可以将所有配置的服务全部启动起来。
使用Docker Compose的三个步骤:
- 使用Dockerfile定义环境,这样可以确保其在任意地方运行
-
使用docker-compose.yml文件定义服务,这样它们就可以在独立环境中一起运行
-
运行docker-compose up使用docker-compose启动所有应用
Docker Compose可以管理应用的整个生命周期:
- 启动、停止、重建服务
-
查看服务的运行状态
-
流式输出服务日志
-
对服务执行一次性命令
二、Docker Compose安装
二进制安装:
下载地址:https://github.com/docker/compose/releases
pip安装:
pip install docker-compose
三、Docker Compose基本示例
1、基本文件及目录设置
创建一个目录:
mkdir composetest cd composetest
在上面的目录中创建一个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) if __name__ == "__main__": app.run(host="0.0.0.0", debug=True)
再创建一个pip.conf文件,内容如下:
[global] index-url = https://mirrors.aliyun.com/pypi/simple/ [install] trusted-host=mirrors.aliyun.com
2、创建一个Dockerfile
仍然在composetest目录中创建一个Dockerfile,内容如下:
FROM python:3.4-alpine ADD . /code WORKDIR /code RUN pip install -r requirements.txt CMD ["python", "app.py"]
3、通过docker-compose.yml定义服务
docker-compose.yml内容如下:
version: '3' services: web: build: . ports: - "5000:5000" redis: image: "redis:alpine"
这个文件定义了两个服务:web和redis。
- web服务使用当前目录的Dockerfile进行构建,并且映射web服务的5000端口到宿主机5000端口。
- redis服务使用一个公共的redis镜像。
4、通过Docker Compose构建并启动服务
docker-compose up
这个时候可以通过http://127.0.0.1:5000来访问这个web服务。
5、修改Compse文件,添加一个挂载点
修改docker-compose.yml,内容如下:
version: '3' services: web: build: . ports: - "5000:5000" volumes: - .:/code redis: image: "redis:alpine"
添加了一个volumes配置项,将当前目录挂载至web容器的/code目录下。
然后我们通过docker-compose up重新构建应用,再次访问,会发现结果与上面完全相同。
6、 更新应用
我们修改本地的app.py,修改Hello World!为Hello from Dokcer,如下:
return 'Hello from Docker! I have been seen {} times.n'.format(count)
这个时候再次访问http://127.0.0.1:5000,发现访问内容也随之修改。
这是因为在上面我们将本地目录挂载进了容器,我们修改本地的app.py就相当于修改了容器内的文件。
四、Docker Compose常用命令说明
在上面的一个简单示例中,我们已经使用了docker-compose up来启动一个docker-compose.yml文件定义的服务。我们刚刚通过docker-compose up虽然启动了服务,当是docker-compose指令却在前台执行,如果需要将其放入后台运行,可以使用-d参数:
docker-compose up -d
docker-compose up还可以使用–scale参数实现服务的扩缩容:
[[email protected] composetest]# docker-compose up -d --scale web=2 Recreating composetest_web_1 ... Recreating composetest_web_1 ... done Creating composetest_web_2 ... done
还可以通过-f选项指定compose文件:
[[email protected] tranning]# docker-compose -f test-compose.yml up -d Creating network "tranning_default" with the default driver Creating network "tranning_frontend" with the default driver Creating network "tranning_backend" with the default driver Creating tranning_visualizer_1 ... done Creating tranning_redis_1 ... done Creating tranning_worker_1 ... done Creating tranning_db_1 ... done Creating tranning_result_1 ... done Creating tranning_vote_1 ... done
需要说明的是,如果使用自动扩容,则web服务不能做端口映射,否则会出现端口冲突的情况
下面我们说一说其他常用的docker-compose命令:
docker-compose ps
[[email protected] composetest]# docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------- composetest_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp composetest_web_1 python app.py
docker-compose stop
[[email protected] composetest]# docker-compose stop Stopping composetest_redis_1 ... done Stopping composetest_web_1 ... done [[email protected] composetest]# docker-compose stop web Stopping composetest_web_1 ... done docker-compose start [[email protected] composetest]# docker-compose start Starting web ... done Starting redis ... done [[email protected] composetest]# docker-compose start web Starting web ... done
docker-compose restart
[[email protected] composetest]# docker-compose restart Restarting composetest_web_1 ... done Restarting composetest_redis_1 ... done
docker-compose run
[[email protected] composetest]# docker-compose run web env PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=72ad8a0682b7 TERM=xterm https://down.d1sc.cn/archives/2022/06/13/5jpqpcer4cx.png" alt="" /> 2、services
我们上面所说的所有服务的定义都是定义在services区域中,接下来,我们学习下services下常用的配置项
image
标明image的ID,这个image ID可以是本地也可以是远程的,如果本地不存在,compose会尝试pull下来
示例:
image: ubuntu image: hub.dz11.com/library/tomcat:8
build
该参数指定Dockerfile文件的路径,compose会通过Dockerfile构建并生成镜像,然后使用该镜像
示例:
build: /path/to/build/dir
command
重写默认的命令,或者说指定启动容器的命令
示例:
command: "/run.sh"
links
链接到其他服务中的容器,可以指定服务名称和这个链接的别名,或者只指定服务名称
示例:
links: - db - db:database - redis
此时,在容器内部,会在/etc/hosts文件中用别名创建几个条目,如下:
172.17.2.100 db 172.17.2.100 database 172.17.2.100 redis
external_links
链接到compose外部启动的容器,特别是对于提供共享和公共服务的容器。在指定容器名称和别名时,external_links遵循着和links相同的语义用法
示例:
external_links: - redis_1 - project_db_1: mysql - project_db_2: postgresql
ports
暴露端口,指定宿主机到容器的端口映射,或者只指定容器的端口,则表示映射到主机上的随机端口
注:当以 主机:容器 的形式来映射端口时,如果使容器的端口小于60,那可能会出现错误,因为YAML会将 xx:yy这样格式的数据解析为六十进制的数据,基于这个原因,时刻记得要将端口映射明确指定为字符串
示例:
ports: - "3000" - "8000:8000" - "49100:22" - "127.0.0.1:8001:8001"
expose
暴露端口,但不需要建立与宿主机的映射,只是会向链接的服务提供
示例:
expose: - "3000" - "8000"
environment
加入环境变量,可以使用数组或者字典,只有一个key的环境变量可以在运行compose的机器上找到对应的值
示例:
environment: RACK_ENV: development SESSION_SECRET: environment: - RACK_ENV: development - SESSION_SECRET:
env_file
从一个文件中引入环境变量,该文件可以是一个单独的值或者一个列表,如果同时定义了environment,则environment中的环境变量会重写这些值
示例:
env_file: - env
cat env RACK_ENV: development
depends_on
定义当前服务启动时,依赖的服务,当前服务会在依赖的服务启动后启动
depends_on: - redis
deploy
该配置项在version 3里才引入,用于指定服务部署和运行时相关的参数
version: '3' services: redis: image: redis:alpine deploy: replicas: 6 update_config: parallelism: 2 delay: 10s restart_policy: condition: on-failure
下面是deploy中常用参数的说明
replicas
指定副本数:
version: '3' services: worker: image: dockersamples/examplevotingapp_worker deploy: replicas: 6
restart_policy
指定重启策略:
version: "3" services: redis: image: redis:alpine deploy: restart_policy: condition: on-failure #重启条件:on-failure, none, any delay: 5s # 等待多长时间尝试重启 max_attempts: 3 #尝试的次数 window: 120s # 在决定重启是否成功之前等待多长时间
update_config
定义更新服务的方式,常用于滚动更新
version: '3.4' services: vote: image: dockersamples/examplevotingapp_vote:before depends_on: - redis deploy: replicas: 2 update_config: parallelism: 2 # 一次更新2个容器 delay: 10s # 开始下一组更新之前,等待的时间 failure_action:pause # 如果更新失败,执行的动作:continue, rollback, pause,默认为pause max_failure_ratio: 20 # 在更新过程中容忍的失败率 order: stop-first # 更新时的操作顺序,停止优先(stop-first,先停止旧容器,再启动新容器)还是开始优先(start-first,先启动新容器,再停止旧容器),默认为停止优先,从version 3.4才引入该配置项
resources
限制服务资源:
version: '3' services: redis: image: redis:alpine deploy: resources: limits: cpus: '0.50' memory: 50M reservations: cpus: '0.25' memory: 20M
healthcheck
执行健康检查
healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] # 用于健康检查的指令 interval: 1m30s # 间隔时间 timeout: 10s # 超时时间 retries: 3 # 重试次数 start_period: 40s # 启动多久后开始检查
network_mode
网络类型,可指定容器运行的网络类型
示例:
network_mode: "bridge" network_mode: "host" network_mode: "none"
dns
自定义dns服务
示例:
dns: 8.8.8 dns: - 223.5.5.5 - 223.6.6.6
3、networks
网络决定了服务之间以及服务和外界之间如何去通信,在执行docker-compose up的时候,docker会默认创建一个默认网络,创建的服务也会默认的使用这个默认网络。服务和服务之间,可以使用服务的名字进行通信,也可以自己创建网络,并将服务加入到这个网络之中,这样服务之间可以相互通信,而外界不能够与这个网络中的服务通信,可以保持隔离性。
在networks中定义一个名为app_net,类型为driver的网络:
version: '2' services: app: image: busybox command: ifconfig networks: app_net: ipv4_address: 172.16.238.10 networks: app_net: driver: bridge enable_ipv6: true ipam: driver: default config: - subnet: 172.16.238.0/24 gateway: 172.168.238.254
4、volumes
version: "3.2" services: web: image: nginx:alpine volumes: - type: volume source: mydata target: /data volume: nocopy: true - type: bind source: ./static target: /opt/app/static db: image: postgres:latest volumes: - "/var/run/postgres/postgres.sock:/var/run/postgres/postgres.sock" - "dbdata:/var/lib/postgresql/data" volumes: mydata: dbdata:
六、Docker Compose案例实践
1、部署一个web集群
项目说明
这是一个典型的web项目,由一个haproxy容器加三个web容器组成。haproxy在前端充当负载均衡器,反向代理到后台三个服务服务。
基本目录结构
首先创建一个compose-haproxy-web的目录,然后在目录里面,创建两个子目录:haproxy和web。
在web目录里包含三个文件: Dockerfile、index.py、index.html
在haproxy目录里包含一个文件: haproxy.cfg
目录结构如下:
compose-haproxy-web/ ├── docker-compose.yml ├── haproxy │ └── haproxy.cfg └── web ├── Dockerfile ├── index.html └── index.py 2 directories, 5 files
web目录下的index.py提供一个简单的http服务,打印出访问者的ip和实际的本地IP,内容如下:
#!/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><h4><font color="blue" size=8><em>HA</em></font> Webpage Visit Results</h4></center>"); 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 < 3: file.write(" >#"+ str(request[pair][1]) +": <font color="red">"+str(request[pair][0])+ "</font> requests " + "from <<font color="blue">"+guest+"</font>> to WebServer <<font color="blue">"+pair[1]+"</font>>>") else: file.write(" >#"+ str(request[pair][1]) +": <font color="maroon">"+str(request[pair][0])+ "</font> requests " + "from <<font color="navy">"+guest+"</font>> to WebServer <<font color="navy">"+pair[1]+"</font>>>") 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()
web目录下index.html文件是一个空文件,在程序启动之后会用到。
web目录下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 bind 0.0.0.0: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
docker-compose.yml内容如下:
version: '3' services: 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"
启动docker-compose:
docker-compose up -d
通过验证,我们可以看到服务正常部署,访问http://127.0.0.1:80也可以完成服务的正常访问。但是在前面,我们讲过,weba和webb以及webc都是由同一个image创建而来,那么我们是否可以使用deploy配置项,直接配置三副本呢?
我们验证一下,修改docker-compose.yml内容如下:
version: '3' services: web: build: ./web expose: - 80 deploy: replicas: 3 haproxy: image: haproxy:latest volumes: - ./haproxy:/haproxy-override - ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro external_links: - compose-haproxy-web_web_1 - compose-haproxy-web_web_2 - compose-haproxy-web_web_3 ports: - "80:80" - "70:70" expose: - "80" - "70"
执行docker-compose up -d:
[email protected]:~/trainning/compose-haproxy-web# docker-compose up -d WARNING: Some services (web) use the 'deploy' key, which will be ignored. Compose does not support 'deploy' configuration - use `docker stack deploy` to deploy to a swarm. compose-haproxy-web_web_1 is up-to-date compose-haproxy-web_haproxy_1 is up-to-date
上面提示deploy不被支持,然后web也只启动了一个。这是为什么呢?
因为deploy在使用的时候,有一些限制,但你的compose文件中出现如下配置项时,deploy就无法使用:
- build
- cgroup_parent
- container_name
- devices
- tmpfs
- external_links
- links
- network_mode
- restart
- security_opt
- stop_signal
- sysctls
- userns_mode
2、使用Docker Compose一键部署zabbix
version: '3' services: mysql-server: hostname: mysql-server container_name: mysql-server image: mysql:5.7 network_mode: host volumes: - /data/mysql5721/data:/var/lib/mysql command: --character-set-server=utf8 environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix zabbix-web-nginx-mysql: hostname: zabbix-web-nginx-mysql container_name: zabbix-web-nginx-mysql image: zabbix/zabbix-web-nginx-mysql:alpine-3.4.11 network_mode: host depends_on: - mysql-server - zabbix-server ports: - 80:80 environment: DB_SERVER_HOST: 127.0.0.1 MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix MYSQL_ROOT_PASSWORD: 123456 ZBX_SERVER_HOST: 127.0.0.1 PHP_TZ: Asia/Shanghai zabbix-server: hostname: zabbix-server-mysql container_name: zabbix-server-mysql image: zabbix/zabbix-server-mysql:alpine-3.4.11 depends_on: - mysql-server network_mode: host ports: - 10051:10051 environment: DB_SERVER_HOST: 127.0.0.1 MYSQL_DATABASE: zabbix MYSQL_USER: zabbix MYSQL_PASSWORD: zabbix MYSQL_ROOT_PASSWORD: 123456 zabbix-agent: hostname: zabbix-agent container_name: zabbix-agent image: zabbix/zabbix-agent:alpine-3.4.11 network_mode: host environment: ZBX_HOSTNAME: monitor ZBX_SERVER_HOST: 127.0.0.1
原文出处:cnblogs -> http://www.cnblogs.com/breezey/p/9426085.html