Docker-Compose 详解

本贴最后更新于 800 天前,其中的信息可能已经时移世改

docker-compose

1. 介绍

一个项目一般会由多个应用服务组成。例如一个Django的web项目,由Django后端服务,数据库,uwsgi服务,nginx反向代理服务等组成。如果使用容器技术当然不会将所有的服务都部署到一个容器中,一般是一个独立的服务一个容器。因此上面的项目需要一个python环境的容器用来运行django后端服务和uwsgi服务,一个数据库容器,一个nginx容器。单独部署时,需要一个个手动部署,构建镜像,添加网络,以及各容器之间的依赖和通信等问题,非常繁琐。

docker-compose就是批量部署容器,并自动构建镜像,处理依赖和通信的工具。只需要在一个YAML文件中配置好应用程序的服务,然后通过docker-compose命令就可以创建并启动配置中的所有服务。

使用docker-compose有三个基本步骤:

  1. 在Dockerfile中定义好你的应用程序的环境,以便在任何地方它都可以复制。
  2. docker-compose.ymal中定义组成应用程序的服务,以便它们可以在一个独立的环境中一起运行。
  3. 运行docker-compose up, docker-compose命令会启动并运行整个应用程序。

一个docker-compose.Yml看起来是这样的:

version: "3.9"  # optional since v1.27.0
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
    links:
      - redis
  redis:
    image: redis
volumes:
  logvolume01: {}

2. 安装

Docker Compose依赖于Docker Engine来完成任何有意义的工作,所以请确保在本地或远程安装Docker Engine。

2.1 在windows和mac上安装

Docker Desktop for Mac和Windows 默认包括Compose命令。因此,Windows和Mac用户不需要单独安装Compose V2。

2.2 在liunx系统上安装

在Linux上,您可以从GitHub上的Compose存储库发布页面下载Docker Compose二进制文件,然后按照下面的步骤来安装。

注意:

对于alpine,需要以下依赖包:

py-pip, python3-dev, libffi-dev, openssl-dev, gcc, libc-dev, rust, cargo and make.

  1. 运行此命令下载Docker Compose的当前稳定版本:

     sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    

    要安装不同版本的Compose,请将1.29.2替换为您想要使用的Compose版本。

  2. 添加执行权限

     sudo chmod +x /usr/local/bin/docker-compose
    
  3. 测试安装是否成功

    $ docker-compose --version
    docker-compose version 1.25.0
    

上面这种手动安装容易出现问题,推荐使用下面的pip安装。

通过pip安装

Compose可以使用pip从pypi安装。如果您使用pip安装,我们建议您使用virtualenv,因为许多操作系统有与docker-compose依赖项冲突的python系统包。

 pip install docker-compose

3. 基本使用

接下来我们通过运行一个简单的python web应用来学习docker-compose命令。

3.1 第一步: 编写python程序

  1. 创建一个项目文件夹

     mkdir composetest
     cd composetest
    
  2. 在项目目录下创建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)
    

    在上面的程序中,redis的主机名为'redis',并使用默认端口6379

  3. 在你的项目目录中创建另一个名为requirements.txt的文件,并粘贴如下内容:

    flask
    redis
    

3.2 第二步:创建一个Dockerfile

在这个步骤中,我们会构建一个镜像。该映像包含Python应用程序所需的所有依赖项,包括Python本身。

在项目根目录创建文件Dockerfile,内容如下:

# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]

这告诉Docker:

3.3 第三步:在compose file中定义服务

在项目根目录中创建文件docker-compose.yml,并在其中编写如下内容:

version: "3.9"
services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

这个compose file定义了两个服务webredis

Web service

web 服务会使用项目当前目录下的dockerfile构建的镜像。 然后它将容器的5000端口绑定到主机的5000端口上。

redis service

redis服务使用从Docker Hub下载的公共redis镜像。

3.4 第四步:使用compose命令构建和运行应用

  1. 从项目目录,通过运行docker-compose up启动应用程序。

    $ docker-compose up
    Creating composetest_web_1   ... done
    Creating composetest_redis_1 ... done
    Attaching to composetest_redis_1, composetest_web_1
    redis_1  | 1:C 14 Oct 2021 11:34:42.291 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    redis_1  | 1:C 14 Oct 2021 11:34:42.291 # Redis version=6.2.1, bits=64, commit=00000000, modified=0, pid=1, just started
    redis_1  | 1:C 14 Oct 2021 11:34:42.291 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
    redis_1  | 1:M 14 Oct 2021 11:34:42.291 * monotonic clock: POSIX clock_gettime
    redis_1  | 1:M 14 Oct 2021 11:34:42.292 * Running mode=standalone, port=6379.
    redis_1  | 1:M 14 Oct 2021 11:34:42.292 # Server initialized
    redis_1  | 1:M 14 Oct 2021 11:34:42.294 * Ready to accept connections
    web_1    |  * Serving Flask app 'app.py' (lazy loading)
    web_1    |  * Environment: production
    web_1    |    WARNING: This is a development server. Do not use it in a production deployment.
    web_1    |    Use a production WSGI server instead.
    web_1    |  * Debug mode: off
    web_1    |  * Running on all addresses.
    web_1    |    WARNING: This is a development server. Do not use it in a production deployment.
    web_1    |  * Running on http://192.168.80.3:5000/ (Press CTRL+C to quit)
    

    compose下载了一个Redis镜像,为代码构建了一个镜像,并启动定义好的服务。在本例中,代码在构建时静态地复制到镜像中。

  2. 访问服务程序

    在浏览器中输入http://localhost:5000/或者http://127.0.0.1:5000/访问我们运行的web服务程序。

    image.png

  3. 刷新页面

    数字应该增加。

    image.png

  4. 切换到另一个终端并输入docker image ls查询所有本地镜像

    image.png

  5. 停止应用

    直接在当前运行终端Ctrl + C,或者是再开启一个终端在项目目录下运行docker-compose down关闭运行的应用。

3.5 第五步:添加挂载点

编辑docker-compose.yml,给web服务添加挂载点。

version: "3.9"
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_ENV: development
  redis:
    image: "redis:alpine"

volumes键将主机上的项目目录(当前目录)挂载到容器内的/code中,并允许动态地修改代码,而不必重新构建映像。

environment键设置FLASK_ENV环境变量,该变量告诉flask以开发模式运行并在代码发送更改时重新加载。这种模式只能在开发中使用。

3.6 第六步:通过compose重新构建并运行应用

在项目目录下运行docker-compose up使用更新后的compose文件重新构建并运行应用。

image.png

3.7 第七步:更新应用

因为现在使用卷将应用程序代码挂载到容器中,所以您可以对其代码进行更改并立即查看更改,而无需重新构建镜像。

修改app.py中的返回问候语,例如:

return 'Hello from Docker! I have been seen {} times.\n'.format(count)

在浏览器中刷新应用程序。欢迎语应该更新,计数器应该仍然在增加。

image.png

3.8 第八步:实验一下其他命令

如果你想在后台运行你的服务,你可以将-d标志(用于“分离”模式)传递给docker-compose up,并使用docker-compose ps来查看当前正在运行的服务:

image.png

docker-compose run命令允许您为您的服务运行一次性命令。例如,要查看web服务可用的环境变量:

docker-compose run web env
Creating composetest_web_run ... done
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=7929330f0f39
TERM=xterm
FLASK_ENV=development
LANG=C.UTF-8
GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D
PYTHON_VERSION=3.7.10
PYTHON_PIP_VERSION=21.0.1
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/b60e2320d9e8d02348525bd74e871e466afdf77c/get-pip.py
PYTHON_GET_PIP_SHA256=c3b81e5d06371e135fb3156dc7d8fd6270735088428c4a9a5ec1f342e2024565
FLASK_APP=app.py
FLASK_RUN_HOST=0.0.0.0
HOME=/root

如果使用docker-compose up -d命令启动服务,停止服务可以使用命令

docker-compose stop

也可以使用down命令删除所有,完全删除容器。通过——volumes来删除Redis容器使用的数据卷:

docker-compose down --volumes

这些就是docker-compose的基本使用方法。

4. Compose file

Compose file是一个定义servicesnetworksvolumes的YAML文件。Compose file的默认路径是./docker-compose.yml。yaml文件的后缀ymlyaml都支持。

下面介绍Compose file中的常用指令。

version

指定compose file的版本。

networks

创建网络。

services

定义服务程序,每个服务对应会创建一个容器。

build

配置构建。

  1. 设置为一个字符串,指定构建时的上下文路径:

    version: "3.9"
    services:
      webapp:
        build: ./dir
    
  2. 设置为一个对象,在其中设置context,Dockerfile,args

    version: "3.9"
    services:
      webapp:
        build:
          context: ./dir
          dockerfile: Dockerfile-alternate
          args:
            buildno: 1
    

当同时设置buildimage配置项时,Compose会使用image中指定的webapptag来命名构建的图像:

build: ./dir
image: webapp:tag

command

覆盖容器默认的启动命令。

command: bundle exec thin -p 3000

也可以是一个列表

command: ["bundle", "exec", "thin", "-p", "3000"]

container_name

指定启动容器的名字

container_name: my-web-container

depends_on

表示服务之间的依赖关系。 服务依赖会导致以下行为:

version: "3.9"
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres

在使用depends_on时需要注意:

entrypoint

覆盖容器默认的entrypoint

entrypoint: /code/entrypoint.sh

也可以写成列表的形式

entrypoint: ["php", "-d", "memory_limit=-1", "vendor/bin/phpunit"]

注意设置了entrypoint后,不仅会覆盖服务镜像Dockerfile中的ENTRYPOINT指令还会忽略其中的CMD指令。

environment

设置容器运行时的环境变量。你可以使用数组,也可以使用字典。 任何布尔值(true, false, yes, no)都需要用引号括起来,以确保它们不会被YML解析器转换为TrueFalse

environment:
  RACK_ENV: development
  SHOW: 'true'
  SESSION_SECRET:

expose

暴露端口,但不映射到宿主机,只被连接的服务访问。只能指定内部端口。

expose:
  - "3000"
  - "8000"

image

指定容器启动的镜像。可以是镜像名,也可以是镜像ID的部分。

image: redis
image: ubuntu:18.04
image: a4bc65fd

如果镜像不存在compose会pull它。如果还制定了build指令,将作为构建后的镜像的名字。

network_mode

设置网络模式。与docker客户端的--network参数的取值一样。

network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"

networks

配置容器连接的网络,引用顶级 networks 下的条目 。

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

ports

端口映射。

有三种格式:

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"
  - "127.0.0.1::5000"
  - "6060:6060/udp"
  - "12400-12500:1240"

restart

设置重启策略。

no是默认的重新启动策略,在任何情况下都不会重新启动容器。

当指定always时,容器总是重新启动。

如果退出码指示一个on-failure错误,on-failure策略将重新启动容器。

设置为unless-stop则除非容器被停止(手动或其他方式),否则该容器总是会重新启动。

restart: "no"
restart: always
restart: on-failure
restart: unless-stopped

volumes

挂着一个主机路径或者绑定一个命名卷到服务。

可以将主机路径挂载为单个服务的定义的一部分,不需要在顶级volumes中定义它。

但是,如果您想跨多个服务重用卷,那么在顶级卷键中定义一个命名卷。

简单语法格式是:[SOURCE:]TARGET[:MODE]

volumes:
  # Just specify a path and let the Engine create a volume
  - /var/lib/mysql

  # Specify an absolute path mapping
  - /opt/data:/var/lib/mysql

  # Path on the host, relative to the Compose file
  - ./cache:/tmp/cache

  # User-relative path
  - ~/configs:/etc/configs/:ro

  # Named volume
  - datavolume:/var/lib/mysql

更多信息详见官方文档

5. compose v2

新的compose V2版本支持将compose命令作为docker cli的一部分,也即是可以去掉docker-compose命令中的-,直接使用docker compose命令。

v2版本的做了很多更新和优化,未来会取代v1版本。

1. 安装

1.1 在windows和mac上安装

Docker Desktop for Mac和Windows 3.2.1及以上版本包括新的Compose命令和Docker CLI。因此,Windows和Mac用户不需要单独安装Compose V2。

1.2 在linux上安装

直接通过从项目发布页面下载适合您系统的二进制文件并将其复制为$HOME/.docker/cli-plugins目录下的docker-compose文件。

  1. 运行以下命令下载Docker Compose的当前稳定版本:
 mkdir -p ~/.docker/cli-plugins/
 curl -SL https://github.com/docker/compose/releases/download/v2.0.1/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose

这个命令将为当前活动用户安装Compose V2到$HOME目录下。为系统上的所有用户安装Docker Compose,替换~/.docker/cli-plugins//usr/local/lib/docker/cli-plugins

  1. 添加可执行权限

     chmod +x ~/.docker/cli-plugins/docker-compose
    
  2. 测试是否安装成功

    $ docker compose version
    Docker Compose version v2.0.1
    
回帖
请输入回帖内容 ...