Docker三劍客之Compose

What is Compose?
node

    Compose是Docker官方的開源項目,負責實現對Docker容器集羣的快速編排。經過Compose能夠定義和運行多容器docker環境,使用Compose,可使用模版文件(YAML文件)來配置應用的服務。而後,經過compose相關命令,能夠建立和啓動全部應用服務。
python

Compose應用場景git

    使用Dockerfile模版文件,能夠很方便的定義一個單獨的應用容器。然而,在平常工做中,常常碰到須要多個容器相互配合來完成某項任務的狀況。例如,要實現一個Web項目,除了Web服務容器自己,每每還須要在加上後端的數據庫服務容器,甚至還包括負載均衡容器等。Compose剛好知足這樣的需求,用戶經過單獨的docker-compose.yml模版文件來定義一組相關聯的應用容器爲一個項目。
github

Compose工做原理圖web

image.png

Compose中的兩個重要概念:redis

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

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

Compose 的默認管理對象是項目,經過子命令對項目中的一組容器進行便捷地生 命週期管理。
安裝Compose
flask

Compose能夠安裝在衆多不一樣的平臺下,如:MacOS,Windows,Other 64-bit Linux。安裝Compose方式也有不少,如pip方式安裝、二進制包安裝、容器中執行等等方式。後端

Linux下安裝Compose

安裝 Compose 以前,要先安裝 Docker(須要 Docker Engine 1.7.1+)。

下載最新Compose版本:

[root@centos7 ~]# sudo curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

添加執行權限:

[root@centos7 ~]# chmod +x /usr/local/bin/docker-compose

檢查安裝:

[root@centos7 ~]# docker-compose --version
docker-compose version 1.22.0, build f46880fe

卸載Compose

若是使用curl安裝,去卸載Comose:

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

Compose使用

使用Compose基本上分爲三步:

    1.使用Dockerfile定義應用程序的環境,以即可以在任何地方進行復制。

    2.在docker-compose.yml中定義構成應用程序的服務,以便它們能夠在隔離環境中一塊兒運行。

    3.運行docker-compose up和Compose啓動並運行整個應用程序。

    爲了實現上述編排與部署的原理,能夠從Docker Comose官網上的一個例子開始入手。

第一步:設置

定義應用程序的依賴項。

1.建立項目目錄:

[root@centos7 ~]# mkdir composetest
[root@centos7 ~]#  cd composetest

2.建立一個名爲app.py的應用,內容以下:

[root@centos7 composetest]# cat app.py 
#!/usr/bin/python3
# coding=utf-8
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)

這是一個基於Python的輕Web的Flask應用,因此看到應用裏有.route('/'),即反問根目錄,而後返回一個從Redis裏讀取出來的值,該值經過自加來統計訪問次數。最後Web容器在0.0.0.0上監聽默認端口5000.

3.建立另外一個文件名爲requirements.txt指定python依賴包:flask和redis,內容以下:

[root@centos7 composetest]# cat requirements.txt 
flask
redis

第二步:建立一個Dockerfile文件

咱們來寫一個 Dockerfile 來定義 Docker 鏡像,此鏡像包含了 Python 的依賴包和 Python 環境。

一樣在此目錄下,咱們建立一個 Dockerfile 文件。

[root@centos7 composetest]# cat Dockerfile 
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python3", "app.py"]

注:我本地環境使用python2.7和python3兼容模式,因此須要指定python3去執行app.py文件。

代碼表示「:

  • 繼承python3.4基礎鏡像

  • 將當前目錄.影射到/code下

  • 設置工做目錄/code

  • 安裝python依賴關係包

  • 啓動app應用程序

第三步:Compose文件定義服務

建立一個名爲docker-compose.yml文件,內容以下:

[root@centos7 composetest]# cat docker-compose.yml 
version: '3'
services: 
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

Compose文件定義了兩個服務,web服務和redis服務,web服務:

  • 使用從當前目錄中的Dockerfile構建的映像。

  • 將容器上的公開端口5000轉發到主機上的端口5000。 咱們使用Flask Web服務器的默認端口5000。

redis服務使用從Docker Hub註冊表中提取的公共Redis映像。

    這裏是編排部署核心所在,在這個YAML文件裏,能夠看到高級別的key:web和redis,這意味着用Compose定義了由兩個「服務」組成的Docker集羣。其中第一個服務叫web,它從當前目錄的Dockerfile build獲得;以後在容器中運行python app.py;把容器內的5000端口映射到宿主機的5000端口;掛載執行這些操做所在的目錄到容器/code目錄下。以後,代碼修改就在容器中體現。

    第二個服務redis直接使用已有的redis鏡像,Dockerfile沒必要另外編寫。

    接下來執行一句docker-compose up就能夠了,嘗試訪問一下宿主機的5000端口,若是沒什麼問題能看到容器裏的python web服務統計訪問次數了。

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

在項目目錄中,經過docker-compose up命令運行應用服務。

[root@centos7 composetest]# docker-compose up
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Creating network "composetest_default" with the default driver
Building web
Step 1/5 : FROM python:3.4-alpine
3.4-alpine: Pulling from library/python
4fe2ade4980c: Pull complete
7cf6a1d62200: Pull complete
599ae3a07d9d: Pull complete
1acdc2ab10cd: Pull complete
2c4249dd0b02: Pull complete
Digest: sha256:7087f61b8d11919f24d7f6115327683a85aecaa050019bd4b35042261e8d7773
Status: Downloaded newer image for python:3.4-alpine
 ---> 90d3f9764c4d
Step 2/5 : ADD . /code
 ---> 97ce6a2665ed
Step 3/5 : WORKDIR /code
 ---> Running in b959e84e8dcc
Removing intermediate container b959e84e8dcc
 ---> 85d8fefdf4ff
Step 4/5 : RUN pip install -r requirements.txt
 ---> Running in 2b07e63ee082
Collecting flask (from -r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB)
Collecting redis (from -r requirements.txt (line 2))
  Downloading https://files.pythonhosted.org/packages/3b/f6/7a76333cf0b9251ecf49efff635015171843d9b977e4ffcf59f9c4428052/redis-2.10.6-py2.py3-none-any.whl (64kB)
Collecting Jinja2>=2.10 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB)
Collecting itsdangerous>=0.24 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz (46kB)
Collecting click>=5.1 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/fa/37/45185cb5abbc30d7257104c434fe0b07e5a195a6847506c074527aa599ec/Click-7.0-py2.py3-none-any.whl (81kB)
Collecting Werkzeug>=0.14 (from flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB)
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask->-r requirements.txt (line 1))
  Downloading https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz
Building wheels for collected packages: itsdangerous, MarkupSafe
  Running setup.py bdist_wheel for itsdangerous: started
  Running setup.py bdist_wheel for itsdangerous: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/2c/4a/61/5599631c1554768c6290b08c02c72d7317910374ca602ff1e5
  Running setup.py bdist_wheel for MarkupSafe: started
  Running setup.py bdist_wheel for MarkupSafe: finished with status 'done'
  Stored in directory: /root/.cache/pip/wheels/33/56/20/ebe49a5c612fffe1c5a632146b16596f9e64676768661e4e46
Successfully built itsdangerous MarkupSafe
Installing collected packages: MarkupSafe, Jinja2, itsdangerous, click, Werkzeug, flask, redis
Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-7.0 flask-1.0.2 itsdangerous-0.24 redis-2.10.6
Removing intermediate container 2b07e63ee082
 ---> 23354c79c570
Step 5/5 : CMD ["python3", "app.py"]
 ---> Running in 1de84ec9dcd3
Removing intermediate container 1de84ec9dcd3
 ---> 1cdd437daa30
Successfully built 1cdd437daa30
Successfully tagged composetest_web:latest
WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Pulling redis (redis:alpine)...
alpine: Pulling from library/redis
4fe2ade4980c: Already exists
fb758dc2e038: Pull complete
989f7b0c858b: Pull complete
d5318f13abaa: Pull complete
3521559474dd: Pull complete
af5d048338ef: Pull complete
Digest: sha256:fc78e96c8036b6fa69ce8d4e811ba84b9278e772047a93fb6d5549de4ddecc32
Status: Downloaded newer image for redis:alpine
Creating composetest_redis_1 ... done
Creating composetest_web_1   ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1  | 1:C 27 Sep 08:31:29.854 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 27 Sep 08:31:29.854 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 27 Sep 08:31:29.854 # 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 27 Sep 08:31:29.857 # Not listening to IPv6: unsupproted
redis_1  | 1:M 27 Sep 08:31:29.857 * Running mode=standalone, port=6379.
redis_1  | 1:M 27 Sep 08:31:29.857 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1  | 1:M 27 Sep 08:31:29.858 # Server initialized
redis_1  | 1:M 27 Sep 08:31:29.858 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1  | 1:M 27 Sep 08:31:29.858 # 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.
redis_1  | 1:M 27 Sep 08:31:29.858 * Ready to accept connections
web_1    |  * Serving Flask app "app" (lazy loading)
web_1    |  * Environment: production
web_1    |    WARNING: Do not use the development server in a production environment.
web_1    |    Use a production WSGI server instead.
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: 830-423-564

查看本地網絡狀態,並訪問http://127.0.0.1:5000,以下:

image.png

瀏覽器中訪問docker主機ip,每次刷新網頁會有一個計數:

image.png

此時列出鏡像列表會返回redis和web:image.png

中止應用,能夠在工做目錄中經過docker-compose down中止服務,或者在啓動應用的窗口中經過CTRL+C中止應用:

[root@centos7 composetest]# docker-compose down
Stopping composetest_web_1   ... done
Stopping composetest_redis_1 ... done
Removing composetest_web_1   ... done
Removing composetest_redis_1 ... done
Removing network composetest_default

第五步:編輯Comose文件添加綁定掛載

編輯項目目錄中的docker-compose.yml文件,爲web服務添加綁定掛載:

[root@centos7 composetest]# cat docker-compose.yml 
version: '3'
services: 
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
  redis:
    image: "redis:alpine"

新鍵值對volumes是將本地的項目目錄composetest掛載到容器內的/code目錄下,這樣能夠動態的修改代碼,從而沒必要在從新建立鏡像。

第六步:使用compose從新建立和運行應用

使用docker-compose up從新建立應用:

[root@centos7 composetest]# docker-compose up
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Recreating composetest_web_1 ... done
Starting composetest_redis_1 ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1  | 1:C 28 Sep 01:46:01.941 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1  | 1:C 28 Sep 01:46:01.942 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1  | 1:C 28 Sep 01:46:01.942 # 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 28 Sep 01:46:01.944 # Not listening to IPv6: unsupproted
redis_1  | 1:M 28 Sep 01:46:01.945 * Running mode=standalone, port=6379.
redis_1  | 1:M 28 Sep 01:46:01.945 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1  | 1:M 28 Sep 01:46:01.945 # Server initialized
redis_1  | 1:M 28 Sep 01:46:01.945 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1  | 1:M 28 Sep 01:46:01.945 # 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.
redis_1  | 1:M 28 Sep 01:46:01.945 * DB loaded from disk: 0.000 seconds
redis_1  | 1:M 28 Sep 01:46:01.945 * Ready to accept connections
web_1    |  * Serving Flask app "app" (lazy loading)
web_1    |  * Environment: production
web_1    |    WARNING: Do not use the development server in a production environment.
web_1    |    Use a production WSGI server instead.
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: 328-944-619
web_1    | 192.168.39.1 - - [28/Sep/2018 01:46:13] "GET / HTTP/1.1" 200 -
web_1    |  * Detected change in '/code/app.py', reloading
web_1    |  * Restarting with stat
web_1    |  * Debugger is active!
web_1    |  * Debugger PIN: 328-944-619
web_1    | 192.168.39.1 - - [28/Sep/2018 01:49:48] "GET / HTTP/1.1" 200 -

第七步:修改應用

如今,app.py代碼能夠直接編輯app.py進行修改,如:

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

從新刷新,瀏覽器:

image.png

第八步:嘗試一些其餘命令

若是你但願你的應用程序在後臺運行,你能夠將 -d 標記傳遞給 docker-compose up 並使用 docker-compose ps 來查看當前運行的應用。

$ docker-compose up -d
Starting composetest_redis_1...
Starting composetest_web_1...

$ docker-compose ps
Name                 Command            State       Ports
-------------------------------------------------------------------
composetest_redis_1   /usr/local/bin/run         Up
composetest_web_1     /bin/sh -c python app.py   Up      5000->5000/tcp

docker-compose run 命令容許你爲你的應用程序運行一次性命令。例如,查看哪些環境變量能夠用於 web 服務:

$ docker-compose run web env

經過 docker-compose --help 查看全部可用的命令。

若是你使用 docker-compose up -d 啓動了 Compose,你可能但願在它們運行完成後中止服務:

$ docker-compose stop

你能夠停掉全部一切,使用 down 命令徹底移除容器。傳遞 —volumes 還能夠刪除 Redis 容器中所使用的數據卷。

$ docker-compose down --volumes

這時,你已經看到了 Compose 工做的基礎知識。

Compose工做原理

    Docker-compose的調用過程很是的扁平,以下圖所示。

image.png

                                                                    圖1.compose的一次調用流程    

    以docker-compose up操做爲例,docker-compose更像是docker client加強版,它爲docker client引入「組」的概念,如上圖所示docker-comose定義了一組「服務」來組成一個docker-comose的project,在經過service創建docker-comose.yml參數,從而與container創建關係,最後使用container來完成對docker-py(Docker client的python版)的調用,向 Daemon發起HTTP請求。

    首先,用戶執行的docker-comose up指令調用了命令行的啓動方式。一個docker-compose.yml定義了一個docker-compose的project,docker-compose up操做提供的命令行參數做爲想這個Project的啓動參數交由project模塊去處理。

    而後,若是當前宿主機已經存在與該應用對應的容器,docker-comose將進行行爲邏輯判斷。若是用戶指定能夠從新啓動已有服務,docker-comose就會執行service模塊的容器重啓方式,不然就將直接啓動已有容器。這兩種操做的區別在於前者會中止舊的容器,建立啓動新的容器,並把舊容器移除掉。在這個過程當中建立容器的各項自定義參數都是從docker-compose up指令和docker-compose.yml中傳入。

    接下來,這個方法中完成了一個Docker容器啓動所需的主要參數的封裝,並在Container模塊執行啓動。

    最後,container模塊會調用docker-py客戶端來執行向Docker daemon發起建立容器的POST請求,在交由Docker處理。

    

未完待續..

參考https://docs.docker.com/compose/overview/

           Docker容器與容器雲

相關文章
相關標籤/搜索