七、Docker Compose 入門實踐

本文是《Docker必知必會系列》第七篇,原文發佈於個人博客:悟塵紀

上一篇:Docker必知必會系列(六):基於多階段構建減小鏡像體積降低複雜度

一、Docker Compose 概述

1、Docker Compose 是什麼

Compose 項目是 Docker 官方支持的開源項目,基於 Python 編寫,用於定義和運行多容器Docker應用程序。Compose 使用 YAML 文件來配置應用程序的服務。然後,使用一個命令,就可以從配置中創建並啓動所有服務。

!!! note “”
使用 Dockerfile 模板文件,可以讓用戶很方便的定義一個單獨的應用容器。然而,在日常工作中,經常會碰到需要多個容器相互配合來完成某項任務的情況。例如要實現一個 Web 項目,除了 Web 服務容器本身,往往還需要再加上後端的數據庫服務容器,甚至還包括負載均衡容器等。Compose 剛好可以滿足這樣的需求。

Compose 有着用於管理應用程序整個生命週期的各種命令:

  • 啓動、停止和重建服務
  • 查看正在運行的服務的狀態
  • 實時查看運行服務的日誌輸出
  • 僅執行一次命令即可運行整個服務

2、Compose 使用步驟

使用 Compose 基本上有三個步驟:

  1. 使用 Dockerfile 定義應用程序的環境,這樣它就可以在任何地方複製。
  2. docker-compose. yml 定義組成應用程序的服務,使其可以在一個獨立的環境中一起運行。
  3. 運行 docker-Compose up ,Compose 啓動並運行您的整個應用程序。

3、典型 docker-compose 文件示例

使用 docker-compose 您主要的任務是編寫 docker-compose.yml 文件。以下是一個 WordPress 的 yaml 文件模板:

version: '3'        # 定義版本,不指定默認爲版本 1

services:           # 定義容器,就像 docker run
   db:              # 容器名稱,也是 network 中 DNS 名稱
     image: mysql:5.7   # 鏡像,如果自定義鏡像可以不指定這個參數,而用 build
     volumes:       # 定義數據卷,類似 -v
       - db_data:/var/lib/mysql
       - .:/lxl80   # 掛載當前目錄到容器中的 /lxl80 目錄
     restart: always  # 類似 --restart。'no' 默認,不自動重啓;always 總是自動重啓; on-failure 當失敗時自動重啓;unless-stopped 除非手動停止,否者一直重啓
     environment:   # 定義環境變量,類似 -e
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:      # 第二個容器
     labels:       # 爲容器添加 Docker 元數據(metadata)信息。
       cn.lixl.title: "This label will appear on all containers for the web service"
     depends_on:   # 定義容器之間的關係。啓動 wordpress 時會先啓動 db
       - db
     image: wordpress:latest
     ports:        # 端口,類似 -p
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress

volumes:          # 可選,需要創建的數據卷,類似 docker volume create
  db_data:

networks:         # 可選,需要創建的網絡,類似 docker network create

二、Compose安裝及卸載

1、安裝 Compose

Docker Desktop for Mac/Windows 自帶 docker-compose 二進制文件,安裝 Docker 之後可以直接使用。

$ docker-compose --version
docker-compose version 1.24.1, build 4667896b

在 Linux 上的也安裝十分簡單,從 官方 GitHub Release 處直接下載編譯好的二進制文件即可。

例如,在 Linux 64 位系統上直接下載對應的二進制包。

sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

2、卸載 Compose

如果基於 curl 安裝,通過以下命令卸載Docker Compose :

sudo rm /usr/local/bin/docker-compose

如果基於 pip 安裝,通過以下命令卸載Docker Compose :

pip uninstall docker-compose

三、Docker Compose 入門

關鍵術語

Compose 中有兩個重要的概念:

  • 服務 (service):一個應用的容器,實際上可以包括若干運行相同鏡像的容器實例。

  • 項目 (project):由一組關聯的應用容器組成的一個完整業務單元,在 docker-compose.yml 文件中定義。

可見,一個項目可以由多個服務(容器)關聯而成,Compose 面向項目進行管理。

示例應用介紹

接下來,將構建一個運行在 Docker Compose 上的簡單 Python web 應用程序。 該應用程序使用了 Flask 框架,並在 Redis 維護了一個點擊計數器。

首選,需要確保已經安裝了 Docker 引擎和 Docker Compose。 不需要安裝 Python 或 Redis,因爲它們都是由 Docker 鏡像提供的。

第一步:設置

定義應用程序的依賴關係:

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 容器的主機名。 這裏使用 Redis 的默認端口,6379。

3、在項目目錄中創建另一個叫 requirements.txt 的文件,內容如下:

flask
redis

第二步:創建一個Dockerfile

在這個步驟中,將編寫一個 Dockerfile 來構建一個 Docker 鏡像。鏡像包含 Python 應用程序所需的所有依賴項,包括 Python 本身。

在項目目錄中,創建一個名爲 Dockerfile 的文件,內容如下:

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
COPY . .
CMD ["flask", "run"]

這告訴 Docker:

  • 基於 Python 3.7 鏡像構建
  • 將工作目錄設置爲 /code
  • 設置 flask 命令使用的環境變量
  • 安裝 gcc,以便諸如 MarkupSafe 和 SQLAlchemy 之類的 Python 包可以加速編譯
  • 複製 requirements.txt 並安裝 Python 依賴項
  • 將主機上的項目目錄(當前目錄)複製到鏡像中的 . 工作目錄
  • 將容器的默認命令設置爲 flask run

第三步:用 Compose 文件定義服務

在項目目錄中創建一個名爲 docker-compose.yml 的文件,內容如下:

version: '3'
services:
  web:
    build: .   # 相當於 docker build .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

此 Compose 文件定義了兩個服務:webredis

web服務使用從當前目錄中的 Dockerfile 構建的鏡像。然後將容器和主機綁定到公開端口 5000。 此示例服務使用 Flask web 服務器的默認端口5000。

Redis 服務使用從 dockerhub 註冊表中提取的公共 Redis 鏡像。

第四步:用 Compose 構建和運行應用

1、在項目目錄中,通過運行 docker-compose up 啓動應用程序。

$ docker-compose up
Creating network "composetest_default" with the default driver
Creating composetest_web_1 ...
Creating composetest_redis_1 ...
Creating composetest_web_1
Creating composetest_redis_1 ... done
Attaching to composetest_web_1, composetest_redis_1
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
redis_1  | 1:C 17 Aug 22:11:10.480 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 17 Aug 22:11:10.480 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 17 Aug 22:11:10.480 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
web_1    |  * Restarting with stat
redis_1  | 1:M 17 Aug 22:11:10.483 * Running mode=standalone, port=6379.
redis_1  | 1:M 17 Aug 22:11:10.483 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
web_1    |  * Debugger is active!
redis_1  | 1:M 17 Aug 22:11:10.483 # Server initialized
redis_1  | 1:M 17 Aug 22:11:10.483 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
web_1    |  * Debugger PIN: 330-787-903
redis_1  | 1:M 17 Aug 22:11:10.483 * Ready to accept connections

Compose 會拉取一個 Redis 鏡像,爲您的代碼構建一個鏡像,並啓動您定義的服務。 在這種情況下,代碼會在構建時靜態複製到鏡像中。

2、在瀏覽器中輸入 http://localhost:5000/ ,查看該應用程序的運行情況。

您應該在瀏覽器中看到一條消息,內容爲:

Hello World! I have been seen 1 times.

3、刷新頁面,數字應該會遞增。

Hello World! I have been seen 2 times.

4、切換到另一個終端窗口,鍵入 docker image ls 查看本地鏡像。此時列出的鏡像應返回 rediscomposetest_web

5、要停止應用程序,可以在另一個終端中進入項目目錄運行 docker-compose stop,或者在啓動應用程序的原始終端中按 ctrl + c。如果要停止並清除數據,以便再次啓動後重新計數,可以執行 ``docker-compose down`。

第五步:編輯 Compose 文件添加掛載

在項目目錄中編輯 docker-compose. yml,爲 web 服務添加一個 bind mount

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

新增加 volumes 配置,將主機上的項目目錄(當前目錄)安裝到容器內部的 /code 目錄,使您可以即時修改代碼,而不必重建鏡像。新增 environment 鍵設置了 FLASK_ENV 環境變量,指示 flask run 要在開發模式下運行並在更改時重新加載代碼。此模式僅應在開發中使用。

第六步:重新構建並運行

從項目目錄中,先輸入 docker-compose stop 停止營業,然後輸入 docker-Compose up 以構建帶有更新的 Compose 文件的應用程序,並運行它。

$ docker-compose stop
Stopping composetest_web_1   ... done
Stopping composetest_redis_1 ... done
$ docker-compose up
Recreating composetest_web_1 ... done
Starting composetest_redis_1 ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1  | 1:C 17 Apr 2020 02:25:49.466 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
......
web_1    |  * Serving Flask app "app.py" (lazy loading)
web_1    |  * Environment: development
web_1    |  * Debug mode: on
web_1    |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1    |  * Restarting with stat
web_1    |  * Debugger is active!
web_1    |  * Debugger PIN: 143-909-154

再次檢查瀏覽器中的 Hello World 提示消息,並刷新以查看計數增量。

如果出現運行時錯誤指示找不到應用程序文件,拒絕卷安裝或服務無法啓動,請嘗試啓用文件或驅動器共享。有關更多信息,請參閱 Docker for Mac 上的 文件共享 章節。

第七步:更新應用程序

因爲現在應用程序代碼是使用卷安裝到容器中的,所以可以對代碼進行更改並立即生效,而無需重建鏡像。

  1. 更改 app.py 中的提示語並保存。例如,將 Hello World! 更改爲 Hello from Docker!

    return 'Hello from Docker! I have been seen {} times.\n'.format(count)
    
  2. 在瀏覽器中刷新應用。會發現提示語已更新,並且計數器仍在增加。

第八步:嘗試其它命令

如果要讓服務在後臺運行,可以將 -d 參數(用於“分離”模式)傳遞給 docker-compose up ,並用 docker-compose ps 查看當前正在運行的內容:

$ docker-compose up  -d
Starting composetest_web_1   ... done
Starting composetest_redis_1 ... done
$ docker-compose ps
       Name                      Command               State           Ports
-------------------------------------------------------------------------------------
composetest_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
composetest_web_1     flask run                        Up      0.0.0.0:5000->5000/tcp

docker-compose run 命令允許爲服務運行一次性命令。 例如,查看 web 服務可用的環境變量:

$ docker-compose run web env
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=4b3f1e39dc5d
......
FLASK_APP=app.py
FLASK_RUN_HOST=0.0.0.0
HOME=/root

請參閱 docker-compose --help 以查看其他可用命令。您還可以爲 bash 和 zsh shell 安裝 命令補全 功能,這將自動提示可用的命令。

相關文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章