一文掌握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 &lt<font color="blue">"+guest+"</font>&gt to WebServer &lt<font color="blue">"+pair[1]+"</font>&gt>")        else:          file.write("  >#"+ str(request[pair][1]) +": <font color="maroon">"+str(request[pair][0])+ "</font> requests " + "from &lt<font color="navy">"+guest+"</font>&gt to WebServer &lt<font color="navy">"+pair[1]+"</font>&gt>")      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

本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如果侵犯你的利益,请发送邮箱到 [email protected],我们会很快的为您处理。