0%

Docker-Compose入门篇

Docker-Compose简介

Compose是用于定义和运行多容器Docker应用程序的工具。通过Compose,可以使用YAML文件来配置应用程序的服务。然后使用一个命令,就可以从配置中创建并启动所有服务。Compose可在所有环境中工作:生产、模拟、开发、测试以及CI工作流。

使用Compose基本上是三步流程:

  • 使用Dockerfile定义应用程序的环境,以便可以在任何地方复制它。
  • 在docker-compose.yml中定义组成您的应用程序的服务,以便它们可以在隔离的环境中一起运行。
  • 运行docker-compose up,然后Compose启动并运行整个应用程序。

Docker-Compose项目由Python编写,调用Docker服务提供的API来对容器进行管理。因此,只要所操作的平台支持Docker API,就可以在其上利用Compose来进行编排管理。

参考文档:

安装Compose

在CentOS7机器上,假设已经了Docker,参考Install Docker Compose安装Compose-Docker。如果没有安装Docker,那么参考Docker入门进行安装。

1、安装docker-compose 1.24.1 版本

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

2、添加执行权限

1
2
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

3、验证安装

1
docker-compose --version

Hello World

1、创建测试目录

1
2
mkdir composetest
cd composetest

2、在项目目录中创建一个名为app.py的文件,内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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文件,内容为:

1
2
flask
redis

4、创建Dockerfile,内容为:

1
2
3
4
5
6
7
8
9
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"]

该文件说明:

  • 从Python 3.7镜像像开始构建镜像。
  • 将工作目录设置为/code。
  • 设置flask命令使用的环境变量。
  • 安装gcc,以便诸如MarkupSafe和SQLAlchemy之类的Python包可以编译加速。
  • 复制requirements.txt并安装Python依赖项。
  • 复制当前目录中的所有文件到工作目录。
  • 将容器的默认命令设置为flask run。

有关如何编写Dockerfile的更多信息,参考Docker用户指南Dockerfile参考

5、创建docker-compose.yml,内容为:

1
2
3
4
5
6
7
8
version: '3'
services:
web:
build: .
ports:
- "15000:5000"
redis:
image: "redis:alpine"

该Compose文件定义了两个服务:Web和Redis。
Web服务从Dockerfile构建镜像,启动后容器在5000端口提供服务,然后将容器端口5000绑定到主机端口15000。

6、使用Compose构建和运行应用

1
docker-compose up

7、测试应用

1
curl http://127.0.0.1:15000

Hello World 2.0

1、编辑docker-compose.yml,挂载当前目录到/code

1
2
3
4
5
6
7
8
9
10
11
12
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"

2、运行应用

1
docker-compose up

3、修改app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 2.0! I have been seen {} times.\n'.format(count)

4、测试应用

1
curl http://127.0.0.1:15000

常用命令

创建/销毁容器

1
2
3
4
5
6
7
8
9
10
11
# 创建并运行容器
docker-compose up

# 创建并后台运行容器
docker-compose up -d

# 关闭并删除容器
docker-compose down

# 关闭并删除容器,连带删除容器挂载卷
docker-compose down --volumes

启动/停止容器

1
2
3
4
5
# 关闭容器但不删除容器
docker-compose stop

# 启动容器
docker-compose start

查看容器

1
2
3
4
5
6
# 查看容器
docker-compose ps
docker-compose ps -a

# 查看web服务的环境变量
docker-compose run web env

volume说明

docker使用持久化存储的时候,有两种方式:

  • bind mount方式:挂载宿主机的绝对路径(目录和文件都可以)到容器
  • volume方式:挂载volume(本质是目录)到容器

使用bind mount方式,如果宿主文件夹是空的,不光容器内的文件不会被复制到宿主机器上,容器的内容还会被覆盖为空,对于一些容器内路径文件夹存放config文件的情况,宿主目录为空会导致容器内的对应目录被清空,造成启动错误的问题。
使用volume方式,容器内的文件会被保留在volume中(对应的_data文件夹)内部,也就是文件被复制到宿主机器上.

两种方式都可以使用-v(–volume)和–mount参数,但是,在创建bind mount的时候,使用–volume会自动创建宿主方的文件夹,而–mount不会,因此使用–mount映射不存在的目录,会报错。

docker-compose指定的时候,有一些区别:

  • 使用bind mount的时候,宿主这边可以使用相对路径了(./),不需要显示指定($PWD)
  • 可以在指定volume名称的同时创建volume,需要使用volume:的配置项
1
2
3
4
5
6
7
8
9
10
services:
...
dolphinscheduler-master:
volumes:
- dolphinscheduler-logs:/opt/dolphinscheduler/logs
- dolphinscheduler-shared-local:/opt/soft
#- /xxx/mysql-connector.jar:/opt/dolphinscheduler/libs/mysql-connector.jar
- type: bind
source: /xxx/mysql-connector.jar
target: /opt/dolphinscheduler/libs/mysql-connector.jar

参考文档:

expose和ports

参考文档:

expose

expose暴露的端口,可由连接到同一网络的其他服务访问,但不会在宿主机上发布。
例如:

1
2
3
4
5
6
7
8
9
10
services:
myapp1:
...
expose:
- "3000"
- "8000"
myapp2:
...
expose:
- "5000"

docker ps结果如下:

1
2
3
CONTAINER ID   IMAGE    COMMAND     CREATED     STATUS      PORTS               NAMES
8673c14f18d1 ... ... ... ... 3000/tcp, 8000/tcp bael_myapp1
bc044e180131 ... ... ... ... 5000/tcp bael_myapp2

ports

ports暴露的端口,可由连接到同一网络的其他服务访问,并在宿主机上发布。
例如:

1
2
3
4
5
6
7
8
9
10
services:
myapp1:
...
ports:
- "3000" # container port (3000), assigned to random host port
- "3001-3005" # container port range (3001-3005), assigned to random host ports
- "8000:8000" # container port (8000), assigned to given host port (8000)
- "9090-9091:8080-8081" # container port range (8080-8081), assigned to given host port range (9090-9091)
- "127.0.0.1:8002:8002" # container port (8002), assigned to given host port (8002) and bind to 127.0.0.1
- "6060:6060/udp" # container port (6060) restricted to UDP protocol, assigned to given host (6060)

docker ps结果如下:

1
2
3
4
5
CONTAINER ID   ... PORTS                                                                        NAMES
e8c65b9eec91 ... 0.0.0.0:51060->3000/tcp, 0.0.0.0:51063->3001/tcp, 0.0.0.0:51064->3002/tcp, bael_myapp1
0.0.0.0:51065->3003/tcp, 0.0.0.0:51061->3004/tcp, 0.0.0.0:51062->3005/tcp,
0.0.0.0:8000->8000/tcp, 0.0.0.0:9090->8080/tcp, 0.0.0.0:9091->8081/tcp
127.0.0.1:8002->8002/tcp, 0.0.0.0:6060->6060/udp

ports长语法:

1
2
3
4
5
6
7
8
9
10
services: 
myapp1:
...
ports:
# - "127.0.0.1:6060:6060/udp"
- target: 6060
host_ip: 127.0.0.1
published: 6060
protocol: udp
mode: host

小结

这两种暴露方式,最大的区别在于是否在宿主机上暴露端口,是否对外部网络提供服务。
使用docker ps查看容器时,根据PORTS字段,我们也能判断出该容器是否在宿主机上暴露端口。

但是,个别情况下,虽然我们看到的是端口是3000/tcp,但是依然可能在宿主机上暴露端口。可能是docker/docker-compose某个版本的bug,也可能是yaml文件中的version不匹配,也可能是其他什么原因。
这种情况下,只能找到docker-compose.yml,查看端口映射关系,然后查看宿主机端口开放情况。

Docker-Compose网络问题

docker-compose up的时候,会自动创建一个网桥,占用一个网段,并且添加路由规则。
如果这个网段和现有网段发生了冲突,就会导致一些非预期的网络问题,比如主机突然访问不通了。
解决办法是指定网段,详情参考docker-compose up使用自定义的网段的两种方式

查看路由:

1
2
ip route
route -n

查看docker网段使用情况:

1
2
docker network list
docker network inspect xxx
  • 本文作者: 好好学习的郝
  • 本文链接: https://www.voidking.com/dev-docker-compose/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!源站会及时更新知识点及修正错误,阅读体验也更好。欢迎分享,欢迎收藏~