在我们的Docker教程系列的这一点上,我们已经学会了如何安装Docker,运行一些Nginx容器,在容器中测试MongoDB,启动一个以上的容器,了解Docker网络、DNS、图像、卷,以及更多。你可能已经注意到,在使用Docker命令行界面时,命令可能有些冗长,需要大量记忆要运行哪些命令来完成前面提到的所有任务。这就是Docker Compose的用武之地。通过利用Docker Compose,你可以定义提供服务的多容器应用程序,所有这些都是通过定义一个YAML文件。一旦你的YAML文件完成,你可以运行一个命令来启动一个可能有多个容器、一个网络和一个或多个卷的应用程序。
为什么使用Docker Compose?
Docker Compose是一个命令行工具的组合,与一个配置文件(上面提到的YAML文件)协同工作。为了使用Docker Compose,你需要熟悉构建镜像、运行容器、创建网络以及如何使用卷。软件服务通常不是孤立的。容器是一个单一的进程,而大多数有用的应用程序需要比单一进程更多的东西来提供有用的服务。一个Node容器需要其他的容器,比如Mongo容器或Redis容器来完成有用的工作。Docker Compose为你提供了一种方法,将解决方案的所有部分连接在一起,同时设置网络和卷,而不必在命令行上运行大量的命令。它通过两种方式工作:Docker Compose YAML文件和Docker Compose CLI。
Docker Compose YAML文件
Docker Compose的第一部分是YAML文件。YAML是Yet Another Markup Language的缩写,它是用于Docker Compose配置文件的格式。在YAML文件中,你会指定几件事。
YAML文件定义了。
docker-compose.yml
docker-compose.yml文件有几个[版本],在撰写本文时,版本3是最新的,也是最值得推荐的。版本声明应该始终是docker-compose.yml文件中的第一行。默认使用的文件名是docker-compose.yml,但如果你必须使用-f标志,你可以指定一个不同的名字。在这个文件中,你定义了应用程序堆栈和堆栈中的组件相互作用的方式。
docker-compose.yml模板样本
version: '3.8'
# Specify the compose format that this file conforms to.
services:
# Specify the set of containers that your app is composed of.
servicename1:
# Same as 'docker container run'
# Used as the DNS name inside the network.
build:
# Build an image from a Dockerfile
image:
# Tag or partial image ID. Can be local or remote, Compose will attempt
# to pull if it doesn't exist locally.
# Optional if you use 'build:' command
command:
# Override the default command.
# Optional to replace the default CMD specified by the image
environment:
# Add environment variables. You can use either an array or a dictionary
# Environment variables with only a key are resolved to their values on
# the machine Compose is running on. Same as '-e' in 'docker run'
volumes:
# Same as using '-v' with 'docker container run'
ports:
# Expose ports. Either specify both ports (HOST:CONTAINER)
# or just the container port (a random host port will be chosen).
servicename2:
build:
image:
command:
environment:
volumes:
ports:
volumes: # Optional, same as 'docker volume create'
networks: # Optional, same as 'docker network create'
所以你可以看到为什么你需要熟悉图像、容器、环境变量、网络和卷,因为这些正是你在compose YAML文件中定义的内容。服务 "部分是定义你的应用程序的所有容器的地方。在 "服务 "中,我们看到 "servicename1 "和 "servicename2"。这将代表同一网络上的两个不同的容器。同样,你在这里选择的名字也被用作虚拟网络的DNS名称,所以要仔细选择你的名字。在每个 "servicename "里面,是组成每个容器的东西。当然,这些是像图像、命令、变量和使用中的卷的东西。我们在上面添加了注释,以解释YAML文件中每个键的作用,但通常情况下,该文件看起来会更紧凑。这里是没有注释的文件,你可以看到缩进是如何设置层次结构的。
version:
services:
servicename1:
build:
image:
command:
environment:
volumes:
ports:
servicename2:
build:
image:
command:
environment:
volumes:
ports:
volumes:
networks:
Docker Compose CLI
Docker Compose的第二部分是 **docker-compose**cli工具。这个工具解析YAML配置文件,在最常见的情况下设置本地开发和测试自动化。请注意,Docker Compose在不断发展,也可能在生产或其他方面找到用途。Docker Compose的CLI大大减少了你需要记忆和输入的命令数量。你可以用两个简单的命令走很长的路。
- docker-compose up
- docker-compose down
注意:一定要输入docker-compose而不是docker compose,否则你会得到一个错误,即当前上下文中没有 "compose up "命令(默认)。
Docker Compose CLI命令的完整清单在这里列出。
PS C:\code\> docker-compose
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f ...] [options] [--] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
-f, --file FILE Specify an alternate compose file
(default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name
(default: directory name)
-c, --context NAME Specify a context name
--verbose Show more output
--log-level LEVEL Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--no-ansi Do not print ANSI control characters
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don't check the daemon's hostname against the
name specified in the client certificate
--project-directory PATH Specify an alternate working directory
(default: the path of the Compose file)
--compatibility If set, Compose will attempt to convert keys
in v3 files to their non-Swarm equivalent (DEPRECATED)
--env-file PATH Specify an alternate environment file
Commands:
build Build or rebuild services
config Validate and view the Compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show version information and quit
令人敬畏的合成器
好吧,让我们把橡胶放在道路上。Docker Compose有多强大?嗯,考虑一下这个。假设你想试试Django。有很多先决条件需要处理。你必须在你的系统上安装正确版本的Python,你需要用pip安装Django,你需要配置各种变量,你甚至可能需要设置虚拟环境。有了Docker Compose,这就像几个命令一样简单。一个开始使用Docker Compose的好地方是[Awesome Compose]github资源库。这个资源库是一个精心策划的Docker Compose例子列表,为如何使用Compose文件整合不同的服务并使用Docker Compose管理其部署提供了一个起点。其中包括的一些环境有angular、apache-php、django、flask、Minecraft、nginx、golang、react、node、express、vuejs、traefik、java、WordPress等等。
让我们自己试一试几个例子!
PS C:\code> git clone https://github.com/docker/awesome-compose.git
PS C:\code> cd awesome-compose/django
PS C:\code\awesome-compose\django> docker-compose up
Creating network "django_default" with the default driver
Building web
Step 1/8 : FROM python:3.7-alpine
3.7-alpine: Pulling from library/python
188c0c94c7c5: Pull complete
55578f60cda7: Pull complete
3d0ed0f04a02: Pull complete
98762f4040a9: Pull complete
2eeb36df0351: Pull complete
Digest: sha256:61582ae7cccd4c8e64c79fd559e70ef1dbb5a5bddc8fab51cabfad592e7d5bde
Status: Downloaded newer image for python:3.7-alpine
---> 4d91c1ce4cc8
Step 2/8 : EXPOSE 8000
---> Running in 5c5ddb2d943e
Removing intermediate container 5c5ddb2d943e
---> 915a9a087216
Step 3/8 : WORKDIR /app
---> Running in d9fea7cfae35
Removing intermediate container d9fea7cfae35
---> d6ec540549fe
Step 4/8 : COPY requirements.txt /app
---> 7f0a3dfca478
Step 5/8 : RUN pip3 install -r requirements.txt
---> Running in d38b7eee00eb
Collecting Django==3.0.7
Downloading Django-3.0.7-py3-none-any.whl (7.5 MB)
Collecting environs==7.3.1
Downloading environs-7.3.1-py2.py3-none-any.whl (11 kB)
Collecting pytz
Downloading pytz-2020.1-py2.py3-none-any.whl (510 kB)
Collecting sqlparse>=0.2.2
Downloading sqlparse-0.4.1-py3-none-any.whl (42 kB)
Collecting asgiref~=3.2
Downloading asgiref-3.3.0-py3-none-any.whl (19 kB)
Collecting python-dotenv
Downloading python_dotenv-0.15.0-py2.py3-none-any.whl (18 kB)
Collecting marshmallow>=2.7.0
Downloading marshmallow-3.8.0-py2.py3-none-any.whl (46 kB)
Installing collected packages: pytz, sqlparse, asgiref, Django, python-dotenv, marshmallow, environs
Successfully installed Django-3.0.7 asgiref-3.3.0 environs-7.3.1 marshmallow-3.8.0 python-dotenv-0.15.0 pytz-2020.1 sqlparse-0.4.1
Removing intermediate container d38b7eee00eb
---> 658522092c7f
Step 6/8 : COPY . /app
---> 7b9155a033ae
Step 7/8 : ENTRYPOINT ["python3"]
---> Running in 5c4690dcbf9d
Removing intermediate container 5c4690dcbf9d
---> b23991bc8043
Step 8/8 : CMD ["manage.py", "runserver", "0.0.0.0:8000"]
---> Running in 82d8e32ead64
Removing intermediate container 82d8e32ead64
---> 026aa876dacf
Successfully built 026aa876dacf
Successfully tagged django_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`.
Creating django_web_1 ... done
Attaching to django_web_1
web_1 | Watching for file changes with StatReloader
一切都已建成并准备就绪。在浏览器中访问http://localhost:8000/。

哇!如果你以前手动完成过,你可以体会到刚才的工作是多么的容易完成。当我们访问该页面时,容器会将访问记录在控制台中,如下图所示。
web_1 | [28/Oct/2020 18:13:48] "GET / HTTP/1.1" 200 16351
web_1 | [28/Oct/2020 18:13:48] "GET /static/admin/css/fonts.css HTTP/1.1" 200 423
web_1 | [28/Oct/2020 18:13:48] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 200 86184
web_1 | [28/Oct/2020 18:13:48] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 85692
web_1 | [28/Oct/2020 18:13:48] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 85876
web_1 | Not Found: /favicon.ico
web_1 | [28/Oct/2020 18:13:48] "GET /favicon.ico HTTP/1.1" 404 1974
让我们试试Angular。
PS C:\code\awesome-compose> cd angular
PS C:\code\awesome-compose\angular> docker-compose up

那Vue呢?
PS C:\code\awesome-compose> cd vuejs
PS C:\code\awesome-compose\vuejs> docker-compose up

我一直想试试Flask...
PS C:\code\awesome-compose> cd flask
PS C:\code\awesome-compose\vuejs> docker-compose up

在短短几分钟的时间里,我们只用了很少的精力就能启动几个不同的后端和前端框架。这就是Docker Compose的力量。