本文主要讲解以下两块内容:环境配置的作用及常规使用、服务配置文件的解析以及常规使用
必备知识:
在讲解服务配置文件和环境配置文件之前,首先要对docker以及编排工具compose有一定的了解,然后,才能结合服务配置文件编排整个项目的服务以及其依赖关系等。
环境变量:在容器中生效的全局变量值
环境配置文件:可以替换compose服务配置文件中的属性变量。compose默认读取环境配置文件为“.env”,也可以通过--env-file指定相应的配置文件
compose file:服务编排文件,主要定义了一系列服务的配置信息以及依赖等,主要包括:端口、镜像、环境信息、依赖关系等
注意:此处的环境变量和.env类型的环境配置文件是两个概念。环境变量主要是在compose部署启动服务容器后,在容器中生效的变量;而.env中配置的变量值,主要是在定义服务配置文件时,去替换相应的属性。二者的作用范围不同,前者是服务启动后,在容器中作用的环境变量,后者是为了方便定义服务配置文件而构建变量文件。
在编辑Compose file时,可以通过环境变量的形式来填充变量的值
web:
image: "webapp:${TAG}"
那么如何传入这些环境变量呢?主要是通过创建.env配置文件并定义相关属性,然后通过--env-file来指定我们定义的.env配置文件。
.env使用介绍
1.创建项目目录
mkdir env_test
cd env_test
2.创建编排配置文件docker-compose.yml
vi docker-compose.yml
#内容如下
services:
webapp:
image: '${image}:${tag}'
在该配置文件中,我们将image镜像使用${image}:${tag}替换成对应的变量值
3.创建.env
vi .env
#内容如下
image=training/webapp
tag=latest
注意:compose默认会从当前项目路径加载.env配置文件,如果.env在其他目录的话,需要通过--env-file=/path/.env的方式去加载;同样的,如果配置文件使用其他命名方式的话,也需要使用--env-file=/path/.env_rename来加载指定配置文件
4.通过docker-compose config来校验编排配置文件
#默认读取当前项目路径的.env
[shuchang@docker01 env_test]$ docker-compose config
services:
webapp:
image: training/webapp:latest
version: '3.9'
#读取指定配置文件.env_case2
#.env_case2内容如下
image=test
tag=1.1
[shuchang@docker01 env_test]$ docker-compose --env-file .env_case2 config
services:
webapp:
image: test:1.1
version: '3.9'
可以看到,我们在环境配置文件中定义的变量会作为environment配置项的内容加载到编排配置文件中;同时,通过--env-file指定环境配置文件时,同样能实现变量的赋值替换。
#在docker-compose.yml中追加ports配置项
services:
webapp:
image: '${image}:${tag}'
ports:
- '${host_port}:${container_port}'
#并在.env中配置对应的变量
host_port=8080
container_port=80
#由于.env_case2中并未定义两个变量,会抛出异常
[shuchang@docker01 env_test]$ docker-compose --env-file .env_case2 config
WARNING: The host_port variable is not set. Defaulting to a blank string.
WARNING: The container_port variable is not set. Defaulting to a blank string.
ERROR: The Compose file './docker-compose.yml' is invalid because:
services.webapp.ports contains an invalid type, it should be a number, or an object
#去掉docker-compose.yml中的ports配置项后
[shuchang@docker01 env_test]$ docker-compose --env-file .env_case2 config
services:
webapp:
image: test:1.1
version: '3.9'
容器中设置变量,主要是通过在docker-compose.yml中对应的服务下配置environment项,效果等同于docker-compose run -e variable=value
web:
environment:
- DEBUG=1
同时,还可以在配置env_file配置项,从指定的配置文件中加载环境变量
web:
env_file:
- web-variables.env
首先,我们配置docker-compose.yml,在webapp服务下配置env_file配置项,加载文件中的环境变量到webapp服务容器内
vi docker-compose.yml
#配置内容如下
services:
webapp:
image: '${image}:${tag}'
env_file:
- './webapp.env'
然后定义配置文件webapp.env
vi webapp.env
#内容如下
image=training/webapp
tag=latest
host_port=8080
container_port=80
最后通过docker-compose config来检验配置并输出,可以看到在webapp.env中定义的属性都合并到编排文件的environment配置项中了
[shuchang@docker01 env_test]$ docker-compose config
services:
webapp:
environment:
container_port: '80'
host_port: '8080'
image: training/webapp
tag: latest
image: training/webapp:latest
version: '3.9'
compose file作为compose进行服务编排部署的配置文件,在整个过程中起到了决定性的作用。它可以定义服务的一些基本信息,例如:端口、镜像、数据卷等等;同时,还能声明服务之间的依赖关系,决定服务的启动顺序等。因此,了解compose file的常规配置项是十分有必要的!
compose 默认是直接加载docker-compose.yml作为服务的配置文件的,如需指定其他配置文件,需要通过-f /path/docker-compose-customerized.yml来加载配置文件。
见https://blog.csdn.net/weixin_43762303/article/details/123397714
配置文件允许通过profiles配置项选择性地启用服务来针对各种用途和环境调整 Compose 应用程序模型。
version: "3.9"
services:
frontend:
image: frontend
profiles: ["frontend"]
phpmyadmin:
image: phpmyadmin
depends_on:
- db
profiles:
- debug
backend:
image: ibmcom/backend
db:
image: mysql
当前服务配置文件中,frontend和phpmyadmin分别绑定了profiles['frontend']和profiles['debug'];
没有profiles
属性的服务将始终启用,即在这种情况下运行docker-compose up
只会启动backend
和db
。如需启动上述两个服务,需要通过--profiles指定相应配置
[shuchang@docker01 profiles_example]$ docker-compose up
Starting profiles_example_db_1 ... done
Starting profiles_example_backend_1 ... done
Attaching to profiles_example_db_1, profiles_example_backend_1
db_1 | 2022-03-10 09:48:30+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.28-1debian10 started.
db_1 | 2022-03-10 09:48:31+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
db_1 | 2022-03-10 09:48:31+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.28-1debian10 started.
db_1 | 2022-03-10 09:48:31+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
db_1 | You need to specify one of the following:
db_1 | - MYSQL_ROOT_PASSWORD
db_1 | - MYSQL_ALLOW_EMPTY_PASSWORD
db_1 | - MYSQL_RANDOM_ROOT_PASSWORD
backend_1 | App listening on port 3001!
[shuchang@docker01 profiles_example]$ docker-compose --profile debug up
Starting profiles_example_db_1 ... done
Starting profiles_example_backend_1 ... done
Starting profiles_example_phpmyadmin_1 ... done
Attaching to profiles_example_backend_1, profiles_example_db_1, profiles_example_phpmyadmin_1
backend_1 | App listening on port 3001!
db_1 | 2022-03-10 09:57:49+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.28-1debian10 started.
db_1 | 2022-03-10 09:57:49+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
db_1 | 2022-03-10 09:57:49+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.28-1debian10 started.
db_1 | 2022-03-10 09:57:49+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
db_1 | You need to specify one of the following:
db_1 | - MYSQL_ROOT_PASSWORD
db_1 | - MYSQL_ALLOW_EMPTY_PASSWORD
db_1 | - MYSQL_RANDOM_ROOT_PASSWORD
profiles_example_db_1 exited with code 1
phpmyadmin_1 | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.22.0.4. Set the 'ServerName' directive globally to suppress this message
phpmyadmin_1 | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.22.0.4. Set the 'ServerName' directive globally to suppress this message
phpmyadmin_1 | [Thu Mar 10 09:57:50.215499 2022] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.52 (Debian) PHP/8.0.16 configured -- resuming normal operations
phpmyadmin_1 | [Thu Mar 10 09:57:50.216222 2022] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
因此,通过在compose file中配置profiles属性时,可以配置在多种环境下生效的服务,方便快捷测试。
默认情况下,Compose 读取两个文件,一个docker-compose.yml
和一个可选 docker-compose.override.yml
文件。
如果两个文件中都定义了同样的服务,则会将两个服务的配置进行合并;若需要加载其他compose file,则需要通过-f /path/docker-compose-other.yml 指定不同名称的配置文件
注意:
compose针对image、command和mem_limit这种单值的配置项,会直接用新值替换旧值
针对ports、expose、external_links、dns、dns_search和tmpfs这种多值的配置项,会将多个配置项的值合并到一起,且不会覆盖
针对environment、labels、volumes和devices这几个多值的配置项,若存在交集的话,会用新的值替换旧的值,其他值合并到一起
样例:
分别构建两个配置文件:docker-compose.yml和docker-compose.override.yml
[shuchang@docker01 case1]$ cat docker-compose.yml
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
db:
image: "mysql"
ports:
- "23306:3306"
command: 'cat ./test.txt'
[shuchang@docker01 case1]$ cat docker-compose.override.yml
services:
db:
ports:
- 13306:3306
执行docker-compose config 校验服务编排配置并输出
[shuchang@docker01 case1]$ docker-compose config
services:
db:
command: cat ./test.txt
image: mysql
ports:
- published: 23306
target: 3306
- published: 13306
target: 3306
redis:
image: redis:alpine
web:
build:
context: /home/shuchang/docker/docker-compose_example/case1
environment:
FLASK_ENV: development
ports:
- published: 8000
target: 5000
volumes:
- /home/shuchang/docker/docker-compose_example/case1:/code:rw
version: '3.9'
可以看到,两个配置文件中配置的db服务已经合并到了一起,同时暴露了23306:3306,13306:3306端口。因此,可以得知compose默认会读取docker-compose.yml和docker-compose.override.yml,并将配置合并到一起
但是,如果合并配置后存在冲突的话,就会出现异常!例如:上述合并端口时,是以主机的两个端口映射到了容器的同一个端口,这样是可行的。但是如果是把主机的同一个端口映射到容器的两个不同的端口呢?那么必然会导致端口冲突的问题,无法正常启动!
这里我们修改docker-compose.override.yml文件中的db服务,将ports配置项改为23306:3307,这样就能复现上述的问题
[shuchang@docker01 case1]$ docker-compose up
Starting case1_web_1 ...
Starting case1_redis_1 ...
Creating case1_db_1 ...
Creating case1_db_1 ... error
Starting case1_web_1 ... done
Starting case1_redis_1 ... donebaa2cfa2fcb378b28919b45cbf67e): Bind for 0.0.0.0:23306 failed: port is already allocated
ERROR: for db Cannot start service db: driver failed programming external connectivity on endpoint case1_db_1 (c26e2d7638cf0a470b82295dd0636a9e04fbaa2cfa2fcb378b28919b45cbf67e): Bind for 0.0.0.0:23306 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.
通过-f
在使用-f指定compose file时,需注意如果只指定一个文件时,compose只会读取指定的配置文件,如docker-compose -f docker-compose.origin.yml config,只会加载docker-compose.origin.yml一个文件中定义的服务;而docker-compose -f docker-compose.yml -f docker-compose.origin.yml config 则会将两个配置文件中的服务进行合并。
[shuchang@docker01 case1]$ cat docker-compose.origin.yml
#compose针对image、command和mem_limit这种单值的配置项,会直接用新值替换旧值
#针对ports、expose、external_links、dns、dns_search和tmpfs这种多值的配置项,会将多个配置项的值合并到一起,且不会覆盖
#针对environment、labels、volumes和devices这几个多值的配置项,若存在交集的话,会用新的值替换旧的值,其他值合并到一起
services:
db:
command: '-d'
ports:
- "3306:3306"
web:
ports:
- "8000:4000"
[shuchang@docker01 case1]$ cat docker-compose.yml
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
db:
image: "mysql"
ports:
- "23306:3306"
command: 'cat ./test.txt'
[shuchang@docker01 case1]$ docker-compose -f docker-compose.origin.yml -f docker-compose.yml config
services:
db:
command: cat ./test.txt
image: mysql
ports:
- published: 3306
target: 3306
- published: 23306
target: 3306
redis:
image: redis:alpine
web:
build:
context: /home/shuchang/docker/docker-compose_example/case1
environment:
FLASK_ENV: development
ports:
- published: 8000
target: 4000
- published: 8000
target: 5000
volumes:
- /home/shuchang/docker/docker-compose_example/case1:/code:rw
version: '3.9'
Docker Compose 的extends
关键字可以在不同的文件甚至完全不同的项目之间共享通用配置。如果存在多个重用通用配置选项的服务,那么extends能发挥关键作用。使用extends
您可以在一个地方定义一组通用的服务选项,并从任何地方引用它。
注意:volume_from 和 depend_on 无法通过extends进行共享配置,这样会导致依赖之间的引用冲突;且volume在本地文件定义的话,能够确保各个服务对于数据卷的内容进行更改后,不会影响其他服务的运作。
extends的使用
首先创建compose file,通过extends引用共享配置
vi docker-compose.yml
#内容如下
services:
web:
extends:
file: common-services.yml
service: webapp
上述文件中通过extends引用共享配置common-services.yml中的webapp服务,因此这里需要创建一个common-services配置文件,并构建共享服务webapp
vi common-services.yml
#内容如下
services:
webapp:
build: .
ports:
- "8000:8000"
volumes:
- "/data"
然后,我们通过docker-compose config 校验服务配置并输出相应内容
[shuchang@docker01 extends_example]$ docker-compose config
services:
web:
build:
context: /home/shuchang/docker/docker-compose_example/extends_example
ports:
- published: 8000
target: 8000
volumes:
- /data
version: '3.9'
通过上述内容可以看到extends确实能达到引用共享配置的作用,但是不推荐在共享配置中定义volume和depend_on配置项,存在服务之间的引用错乱,以及数据卷内容变更影响服务运行的问题。