簡單來說, docker compose就是一鍵啟動/關閉多個容器的工具, 它能夠幫你解決容器之間依賴的問題, 哪個先啟動, 依賴哪個容器等.
當開發(fā)的系統(tǒng)越來越復雜, 開發(fā)環(huán)境和部署都沒那么簡單的時候, 可以試試docker compose.
下面會把我實際經(jīng)驗中的一個例子簡化出來空幻,一步步教大家如何搭建docker compose柔逼,對踩過的坑進行總結(jié)铸磅,希望對docker能有更深的了解.
1. 搭建環(huán)境背景
以我目前在做的一個用python開發(fā)的web應用為例, 需要搭建一個依賴mysql, localstack, presto, celery, python flask等多項docker容器.
2. 配置文件
通過官網(wǎng)的介紹, 創(chuàng)建docker-compose.yml
, 配置上面提到的幾個services.
version: '3'
services:
mysql:
# mysql 鏡像
image: registry.docker-cn.com/library/mysql:latest
environment:
# 初始化mysql環(huán)境變量
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: "123456"
# 暴露端口號
ports:
- "3306:3306"
localstack:
image: atlassianlabs/localstack:latest
environment:
# localstack主要是為了模擬aws s3, 方便單元測試
AWS_ACCESS_KEY_ID: unit-test-user
AWS_SECRET_ACCESS_KEY: unit-test-user
AWS_DEFAULT_REGION: cn-north-1
AWS_DEFAULT_OUTPUT: text
SERVICES: s3
ports:
- "4572:4572"
presto:
# presto在我的另外一篇文章中有寫如何制作鏡像 http://www.reibang.com/p/bb5181008cd7
image: presto:v0.180
ports:
- "8888:8888"
web:
# 這個鏡像可以根據(jù)代碼中依賴的包進行build, 節(jié)省每次安裝的時間
image: python-web-base:v0.1
command: bash /base/sbin/docker_compose_web_entrypoint.sh
# 暴露端口號, 成功啟動之后可以通過 http://localhost:8081 進行訪問
ports:
- "8081:8081"
# 環(huán)境變量的設置
environment:
S3_PORT: 4572
S3_HOST: localstack
AWS_ACCESS_KEY_ID: unit-test-user
AWS_SECRET_ACCESS_KEY: unit-test-user
AWS_DEFAULT_REGION: cn-north-1
AWS_DEFAULT_OUTPUT: text
# 在docker-compose中, 想要在web service中訪問
# mysql, localstack or presto, 需要給一個hostname,
# hostname跟service name一致.
PRESTO_HOST: presto
MYSQL_HOST: mysql
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: "123456"
depends_on:
- mysql
- localstack
- presto
volumes:
# code base
- .:/base
# query result shared volume: /tmp/
- /tmp:/tmp
celery:
image: python-web-base:v0.1
command: bash /base/sbin/docker_compose_celery_entrypoint.sh
environment:
C_FORCE_ROOT: "true"
PRESTO_HOST: presto
MYSQL_HOST: mysql
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: "123456"
AWS_ACCESS_KEY_ID: unit-test-user
AWS_SECRET_ACCESS_KEY: unit-test-user
AWS_DEFAULT_REGION: cn-north-1
AWS_DEFAULT_OUTPUT: text
depends_on:
- mysql
- presto
- localstack
volumes:
# code base
- .:/base
# query result shared volume: /tmp/
- /tmp:/tmp
完整的代碼我放到了github中 https://github.com/yamyamyuo/docker/tree/master/docker-compose
3. 遇到的坑
3.1 host name問題
配置mysql的時候由于不知道docker-compose中網(wǎng)絡通信是怎么樣的, 就用localhost:3306 或者127.0.0.1:3306去連mysql, 總是報錯, 無法連接該mysql. 發(fā)現(xiàn)原來在docker-compose環(huán)境下, 不管是mysql還是其他servers如presto, 想要連接這些服務, 都要用這些服務的名字進行連接. 如下所示
version: '3'
services:
mysql:
...
presto:
...
localstack:
...
可以連接的服務的名稱分別為mysql
, presto
和localstack
. 于是我在環(huán)境變量中export這些HOST name, 方便我在程序中去判斷是否存在這些環(huán)境變量, 如果有的話就連接這個hostname.
3.2 服務啟動的先后順序
當mysql還沒有成功啟動, celery會一直報錯, 并不斷地重復連接mysql, 于是我想設置這些服務的啟動先后順序, 用了docker compose的 depens_on, 但是depens_on只是表達服務之間的依賴關系, 并不會按照次序來啟動service.
depends_on
does not wait fordb
andredis
to be “ready” before startingweb
- only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.
看來如果想讓web
或者celery
服務等mysql
啟動完畢后再啟動, 需要一個wait-for-it
腳本的幫忙. 這個人寫的腳本還比較清晰簡單的: https://github.com/yamyamyuo/wait-for-it
可以在command
添加一個腳本, 腳本中使用wait-for-it
去輪詢依賴的services, 一旦services啟動成功, web 和 celery就可以繼續(xù)進行啟動了.
3.3 暴露端口號
服務對外暴露的端口號不要忘記填寫, 否則其他docker container無法找到該服務. 注意事項:
當通過HOST:CONTAINER
格式來映射端口號的時候, 低于60的端口號會有錯誤提示, 因為YAML解析格式例如 xx:yy
的數(shù)字是基于base-60的. 因此強烈建議用雙引號把 "HOST:CONTAINER" 括起來.
3.4 volumes
為了能夠持久化和共享容器中的數(shù)據(jù), Docker提出了volume的概念. Volume可以讓容器中的聯(lián)合文件系統(tǒng), 以目錄或文件的形式存于宿主機上.
我最初遇到的一個問題是celery
service 通過異步的方式執(zhí)行一些任務, 任務結(jié)束后會把結(jié)果寫到本地文件, web
service 查詢的時候會到本地文件中查看是否有相關結(jié)果. 這個時候volume排上用場. 只要把容器內(nèi)用到的文件地址映射到宿主機, 同時讓web
和celery
service 都共享該volume即可.
以上就是本次docker compose遇到的一些問題, 如有問題可以留言~