小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。
Docker 进阶 | Docker Compose
背景
以前通过DockerFile 使用 Docker Build 命令生成镜像 通过 Docker Run 去执行, 都是手动去操作 并且是单个容器 。如果有100 个微服务, 并且都存在依赖关系, 那我们该去怎么维护呢?使用 Docker Compose 就可以轻松高效的管理容器。[定义和运行多个容器]
官方介绍
-
Compose 是一个
定义
和运行
多个容器的程序。 -
需要 Yaml file 配置文件
-
single command 命令
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.
所有的环境都可以使用 Docker compose
Compose works in all environments: production, staging, development, testing, as well as CI workflows. You can learn more about each case in Common Use Cases.
使用步骤
Using Compose is basically a three-step process:
- Define your app’s environment with a
Dockerfile
so it can be reproduced anywhere.- Dockerfile 保证我们的项目在任何地方可以运行
- Define the services that make up your app in
docker-compose.yml
so they can be run together in an isolated environment.-
services 什么是服务?
-
Docker-compose.yml 这个文件怎么写?
-
- Run
docker compose up
and the Docker compose command starts and runs your entire app. You can alternatively rundocker-compose up
using the docker-compose binary.- 启动项目
作用: 批量容器编排。
Compose 是 Docker 官方的开源项目, 独立项目, 需要安装
Dockerfile
让程序在任何地方运行。Web服务, redis,mysql,nginx,多个容器, 我们可以写一个 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: {}
docker-compose up
一键上线所有服务
Compose: 重要概念
- 服务 services, 应用(web, redis,mysql) 使用 compose 进行编排
- 项目 project。 一组关联的容器
安装
-
下载
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 # 备用地址: 国内镜像 sudo curl -L "https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 423 100 423 0 0 177 0 0:00:02 0:00:02 --:--:-- 177 100 12.1M 100 12.1M 0 0 3832k 0 0:00:03 0:00:03 --:--:-- 31.4M # 查看下载结果 $ cd /usr/local/bin [root@VM-8-10-centos ~]# cd /usr/local/bin [root@VM-8-10-centos bin]# ll 总用量 12476 -rwxr-xr-x 1 root root 383 12月 10 2019 chardetect -rwxr-xr-x 1 root root 389 12月 10 2019 cloud-init -rwxr-xr-x 1 root root 1781 12月 10 2019 cloud-init-per -rw-r--r-- 1 root root 12737304 10月 1 14:26 docker-compose # 下载成功
-
授权
$ sudo chmod +x /usr/local/bin/docker-compose # 授权 $ docker-compose version # 测试安装结果 docker-compose version 1.29.2, build 5becea4c docker-py version: 5.0.0 CPython version: 3.7.10 OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019 # 安装成功
体验 Get started
Python 应用: 计数器, 使用 Redis 计数
1.Setup : Define the application dependencies
创建项目需要的依赖文件~
# 创建项目存储目录
$ cd ~
$ mkdir app
$ cd app
# 创建项目文件阿基
$ mkdir composetest
$ cd composetest
# 创建 app.py 文件
$ vim app.py # 源码在下面
# 创建 requirements.txt 写上项目需要的依赖~
$ vim requirements.txt
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)
requirements.txt
flask
redis
2.Create a Dockerfile
创建 Dockerfile
$ vim Dockerfile
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"]
3.Define services in a Compose file
在 Compose 里面定义服务
vim docker-compose.yml
docker-compose.yml
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
4.Build and run your app with Compose
Build & Run 我们的应用
$ docker-compose up
# 或
$ docker-compose up -d # 后台启动
Building web
Sending build context to Docker daemon 5.632kB
Step 1/10 : FROM python:3.7-alpine
---> a436fb2c575c
Step 2/10 : WORKDIR /code
---> Using cache
---> 02545a7b7f7c
Step 3/10 : ENV FLASK_APP=app.py
---> Using cache
---> ed7fe3f6c9c6
Step 4/10 : ENV FLASK_RUN_HOST=0.0.0.0
---> Using cache
---> 80ea3d59f3f4
Step 5/10 : RUN apk add --no-cache gcc musl-dev linux-headers
---> Running in d2e239100b80
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
^CGracefully stopping... (press Ctrl+C again to force)
[root@VM-8-10-centos composetest]# ^C
[root@VM-8-10-centos composetest]# clear
[root@VM-8-10-centos composetest]# sudo docker-compose up
sudo: docker-compose:找不到命令
[root@VM-8-10-centos composetest]# su docker-compose up
su: 用户 docker-compose 不存在
[root@VM-8-10-centos composetest]# docker-compose up
Building web
Sending build context to Docker daemon 5.632kB
Step 1/10 : FROM python:3.7-alpine
---> a436fb2c575c
Step 2/10 : WORKDIR /code
---> Using cache
---> 02545a7b7f7c
Step 3/10 : ENV FLASK_APP=app.py
---> Using cache
---> ed7fe3f6c9c6
Step 4/10 : ENV FLASK_RUN_HOST=0.0.0.0
---> Using cache
---> 80ea3d59f3f4
Step 5/10 : RUN apk add --no-cache gcc musl-dev linux-headers
---> Running in 7d9a832e54e3
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
(1/13) Installing libgcc (10.3.1_git20210424-r2)
(2/13) Installing libstdc++ (10.3.1_git20210424-r2)
(3/13) Installing binutils (2.35.2-r2)
(4/13) Installing libgomp (10.3.1_git20210424-r2)
(5/13) Installing libatomic (10.3.1_git20210424-r2)
(6/13) Installing libgphobos (10.3.1_git20210424-r2)
(7/13) Installing gmp (6.2.1-r0)
(8/13) Installing isl22 (0.22-r0)
(9/13) Installing mpfr4 (4.1.0-r0)
(10/13) Installing mpc1 (1.2.1-r0)
(11/13) Installing gcc (10.3.1_git20210424-r2)
(12/13) Installing linux-headers (5.10.41-r0)
(13/13) Installing musl-dev (1.2.2-r3)
Executing busybox-1.33.1-r3.trigger
OK: 140 MiB in 48 packages
Removing intermediate container 7d9a832e54e3
---> c6b8ad3388a1
Step 6/10 : COPY requirements.txt requirements.txt
---> b25eb321aea3
Step 7/10 : RUN pip install -r requirements.txt
---> Running in c9b03beaca70
Collecting flask
Downloading Flask-2.0.1-py3-none-any.whl (94 kB)
Collecting redis
Downloading redis-3.5.3-py2.py3-none-any.whl (72 kB)
Collecting Jinja2>=3.0
Downloading Jinja2-3.0.1-py3-none-any.whl (133 kB)
Collecting click>=7.1.2
Downloading click-8.0.1-py3-none-any.whl (97 kB)
Collecting Werkzeug>=2.0
Downloading Werkzeug-2.0.1-py3-none-any.whl (288 kB)
Collecting itsdangerous>=2.0
Downloading itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Collecting importlib-metadata
Downloading importlib_metadata-4.8.1-py3-none-any.whl (17 kB)
Collecting MarkupSafe>=2.0
Downloading MarkupSafe-2.0.1.tar.gz (18 kB)
Collecting typing-extensions>=3.6.4
Downloading typing_extensions-3.10.0.2-py3-none-any.whl (26 kB)
Collecting zipp>=0.5
Downloading zipp-3.6.0-py3-none-any.whl (5.3 kB)
Building wheels for collected packages: MarkupSafe
Building wheel for MarkupSafe (setup.py): started
Building wheel for MarkupSafe (setup.py): finished with status 'done'
Created wheel for MarkupSafe: filename=MarkupSafe-2.0.1-cp37-cp37m-linux_x86_64.whl size=14616 sha256=a2be1498a2fa606910a87342770f0f777eb9ce4a73a209969fbded2bfb5bd0b5
Stored in directory: /root/.cache/pip/wheels/1a/18/04/e3b5bd888f000c2716bccc94a565239f9defc47ef93d9e7bea
Successfully built MarkupSafe
Installing collected packages: zipp, typing-extensions, MarkupSafe, importlib-metadata, Werkzeug, Jinja2, itsdangerous, click, redis, flask
Successfully installed Jinja2-3.0.1 MarkupSafe-2.0.1 Werkzeug-2.0.1 click-8.0.1 flask-2.0.1 importlib-metadata-4.8.1 itsdangerous-2.0.1 redis-3.5.3 typing-extensions-3.10.0.2 zipp-3.6.0
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
Removing intermediate container c9b03beaca70
---> 6ca85fbb3685
Step 8/10 : EXPOSE 5000
---> Running in 58a8698ea25a
Removing intermediate container 58a8698ea25a
---> 313ecb8fbfbd
Step 9/10 : COPY . .
---> 11705881d5c4
Step 10/10 : CMD ["flask", "run"]
---> Running in e2c0d681ab04
Removing intermediate container e2c0d681ab04
---> e1a776378e7e
Successfully built e1a776378e7e
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
a0d0a0d46f8b: Already exists
a04b0375051e: Pull complete
cdc2bb0f9590: Pull complete
8f19735ec10c: Pull complete
ac5156a4c6ca: Pull complete
7b7e1b3fdb00: Pull complete
Digest: sha256:fa785f9bd167b94a6b30210ae32422469f4b0f805f4df12733c2f177f500d1ba
Status: Downloaded newer image for redis:alpine
Creating composetest_web_1 ... done
Creating composetest_redis_1 ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1 | 1:C 01 Oct 2021 06:59:57.739 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 01 Oct 2021 06:59:57.739 # Redis version=6.2.5, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 01 Oct 2021 06:59:57.739 # 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 01 Oct 2021 06:59:57.740 * monotonic clock: POSIX clock_gettime
redis_1 | 1:M 01 Oct 2021 06:59:57.741 * Running mode=standalone, port=6379.
redis_1 | 1:M 01 Oct 2021 06:59:57.741 # 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 01 Oct 2021 06:59:57.741 # Server initialized
redis_1 | 1:M 01 Oct 2021 06:59:57.741 # 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 01 Oct 2021 06:59:57.741 * 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://172.19.0.3:5000/ (Press CTRL+C to quit)
# 启动成功
[root@VM-8-10-centos composetest]# curl localhost:5000
Hello World! I have been seen 2 times.
[root@VM-8-10-centos composetest]# curl localhost:5000
Hello World! I have been seen 3 times.
[root@VM-8-10-centos composetest]# curl localhost:5000
Hello World! I have been seen 4 times.
[root@VM-8-10-centos composetest]# curl localhost:5000
Hello World! I have been seen 5 times.
[root@VM-8-10-centos composetest]# curl localhost:5000
Hello World! I have been seen 6 times.
[root@VM-8-10-centos composetest]# curl localhost:5000
Hello World! I have been seen 7 times.
总结
- 准备应用 app.py
- Dockerfile 应用打包为镜像
- Docker-compose yaml 定义整个服务, 需要的环境
- 启动 compose 项目
docker-compose up
流程
- 创建网络
- 执行 Docker-compose-yml
- 启动所有的服务
$ ls
# 准备的文件
app.py docker-compose.yml Dockerfile requirements.txt
规则
- Docker images 会自动把依赖的镜像全部下载下来
[root@VM-8-10-centos composetest]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
composetest_web latest e1a776378e7e 11 minutes ago 184MB
python 3.7-alpine a436fb2c575c 3 weeks ago 41.9MB
redis 5.0.9-alpine3.11 3661c84ee9d0 17 months ago 29.8MB
- docker service 现在没有在服务中
[root@VM-8-10-centos composetest]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
52a3bb4546dd redis:alpine "docker-entrypoint.s…" 14 minutes ago Up 3 minutes 6379/tcp composetest_redis_1
480ad107851f composetest_web "flask run" 14 minutes ago Up 3 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp composetest_web_1
[root@VM-8-10-centos composetest]# docker service ls # 查看所有的服务
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
默认服务名 文件名_服务名_ _num, 例如, composetest_web_1
_num 代表的是副本数量, 集群状态下使用
-
网络规则
$ docker network ls [root@VM-8-10-centos composetest]# docker network ls NETWORK ID NAME DRIVER SCOPE acaeca217cc5 bridge bridge local 152181e8650e composetest_default bridge local 3edbb9cd9ab0 host host local dad0ff6720e0 none null local
自动帮我们创建了一个网络 composetest_default
项目中的内容都在同个网络下面, 他们之间都可以通过域名访问
mysql:3360
查看网络细节
$ docker network inspect composetest_default "Containers": { "480ad107851fc859c79497f95999b917fbfd75e28ec8994f019a740f74798580": { "Name": "composetest_web_1", "EndpointID": "48252e19ea813a665fdbac7ff456bf893350e5f48b2452de7d3c2b4fe8f867ae", "MacAddress": "02:42:ac:13:00:02", "IPv4Address": "172.19.0.2/16", "IPv6Address": "" }, "52a3bb4546dd6526ff7e0fe11e2c0b33bd1efa8516da353845f84520d45e355f": { "Name": "composetest_redis_1", "EndpointID": "15ddf67cbbdbbad1fc922142a66ef9dfb302ed8a4ba65ad2d8b068228d512015", "MacAddress": "02:42:ac:13:00:03", "IPv4Address": "172.19.0.3/16", "IPv6Address": "" } },
如果在同一个网络下, 我们可以直接通过域名访问。保证高可用。
停止
# 进入项目文件
$ docker-compose down # 默认启动 不加-d 的那种 使用 Ctrl+c
以前都是单个 docker run 启动容器, 现在可以通过 docker-compose 编写 yaml 配置文件, 通过 docker-compose up 一键启动、停止所有服务
总结
- Docker 镜像。 Run => 容器
- DockerFile 构建镜像 => 服务打包
- docker-compose 启动项目 => 编排多个微服务/环境
- Docker 网络