使用 PyYAML 编辑 docker-compose.yml
Editing docker-compose.yml with PyYAML
我有一个非常标准的docker-compose.yml,我需要以编程方式编辑数据库的密码。
由于它是一个 YAML 文件,我认为编辑和转储内容会很简单。
到目前为止,我尝试了 PyYAML,它只是弄乱了 docker-compose 文件,我不知道为什么。
加载和转储相同的内容,破坏了结构。
docker-compose.yml的内容:
version: '2'
services:
web:
container_name: xxx
ports:
- "80:80"
volumes:
- .:/xxx
depends_on:
- mysql
build: .
mysql:
ports:
- "32768:32768"
- "3306:3306"
container_name: xxx-mysql
restart: always
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: 'thiswillbechangeonsetupscript'
MYSQL_DATABASE: 'xxxdb'
volumes:
- ./database:/var/lib/mysql
ports:
- "3306:3306"
这是我加载和转储内容的方式:
import yaml
with open("docker-compose.yml", 'r') as ymlfile:
docker_config = yaml.load(ymlfile)
with open("docker-compose.yml", 'w') as newconf:
yaml.dump(docker_config, newconf)
这就是文件的保存方式。
services:
mysql:
container_name: xxx-mysql
environment: {MYSQL_DATABASE: xxxdb, MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript}
image: mariadb:latest
ports: ['3306:3306']
restart: always
volumes: ['./database:/var/lib/mysql']
web:
build: .
container_name: xxx
depends_on: [mysql]
ports: ['80:80']
volumes: ['.:/xxx']
version: '2'
有什么更好的方法吗?!我错过了什么?
写yaml时需要添加default_flow_style=False
:
import yaml
with open("docker-compose.yml", 'r') as ymlfile:
docker_config = yaml.load(ymlfile)
with open("docker-compose_new.yml", 'w') as newconf:
yaml.dump(docker_config, newconf, default_flow_style=False)
然后您将得到以下输出,除了使用字母顺序书写行外,与您的输入类似:
services:
mysql:
container_name: xxx-mysql
environment:
MYSQL_DATABASE: xxxdb
MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript
image: mariadb:latest
ports:
- 3306:3306
restart: always
volumes:
- ./database:/var/lib/mysql
web:
build: .
container_name: xxx
depends_on:
- mysql
ports:
- 80:80
volumes:
- .:/xxx
version: '2'
请注意,在您原来的 docker-compose.yaml
中,您声明了 ports
变量两次,因此 yaml 解析器只会考虑最后一个变量。要解决此问题,请删除以下行:
ports:
- "3306:3306"
然后,运行 上面解释的写操作给出以下输出:
services:
mysql:
container_name: xxx-mysql
environment:
MYSQL_DATABASE: xxxdb
MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript
image: mariadb:latest
ports:
- 32768:32768
- 3306:3306
restart: always
volumes:
- ./database:/var/lib/mysql
web:
build: .
container_name: xxx
depends_on:
- mysql
ports:
- 80:80
volumes:
- .:/xxx
version: '2'
PyYAML 的默认转储是对叶节点使用流样式([....]
用于序列,{...}
用于映射),因此您至少应该指定 yaml.dump(....., default_flow_style=False)
然后 YAML 规范声明不能保证键的顺序,您看到的是 PyYAML 按排序顺序转储它们。
我可以推荐使用 ruamel.yaml
(免责声明:我是那个包的作者),它的具体目标是允许这种往返,与输入相比,变化最小,通常none 完全没有。包括键顺序、流与块样式、字符串引号等。
还有另一个使用 ruamel.yaml
的原因:如果您 运行 输入此程序:
import sys
import ruamel.yaml
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.indent(sequence=3, offset=1)
with open("docker-compose.yml", 'r') as ymlfile:
data = yaml.load(ymlfile)
yaml.dump(data, sys.stdout)
你会得到一个 DuplicateKeyError:
ruamel.yaml.constructor.DuplicateKeyError: while constructing a mapping
in "docker-compose.yml", line 13, column 5
found duplicate key "ports" with value "[]" (original value: "[]")
in "docker-compose.yml", line 24, column 5
因为 ports
在作为键 mysql
的值的映射中作为键出现两次。根据 YAML 规范(PyYAML 停用的旧 1.1 和较新的 1.2),这是不允许的,但 PyYAML 会静默处理第一个键值对,使端口 32768 未映射。
从输入中删除最后两行后,程序的输出为:
version: '2'
services:
web:
container_name: xxx
ports:
- "80:80"
volumes:
- .:/xxx
depends_on:
- mysql
build: .
mysql:
ports:
- "32768:32768"
- "3306:3306"
container_name: xxx-mysql
restart: always
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: 'thiswillbechangeonsetupscript'
MYSQL_DATABASE: 'xxxdb'
volumes:
- ./database:/var/lib/mysql
希望这足以满足您的预期目的。
请注意,PyYAML 删除了 - "80:80"
中的引号,这很好,因为 80:80
不会被错误地解释为六十进制,但是如果您对端口 25 进行更改 - 80:80
- 25:25
在使用像 PyYAML 这样的 YAML 1.1 解析器(如 docker-compose
所做的那样)时与 - "25:25" (the former equalling
- 1525`)
有很大不同
基于此,我制作了一个实用程序 ruamel.dcw
,它使用此功能来预处理 docker 撰写文件,允许环境变量的默认值(如果它们未设置)和其他一些技巧,写出一个临时文件然后调用 docker-compose -f tmpfile
,你应该使用类似的技术,在 运行.
之后处理你的临时文件
我有一个非常标准的docker-compose.yml,我需要以编程方式编辑数据库的密码。
由于它是一个 YAML 文件,我认为编辑和转储内容会很简单。 到目前为止,我尝试了 PyYAML,它只是弄乱了 docker-compose 文件,我不知道为什么。
加载和转储相同的内容,破坏了结构。
docker-compose.yml的内容:
version: '2'
services:
web:
container_name: xxx
ports:
- "80:80"
volumes:
- .:/xxx
depends_on:
- mysql
build: .
mysql:
ports:
- "32768:32768"
- "3306:3306"
container_name: xxx-mysql
restart: always
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: 'thiswillbechangeonsetupscript'
MYSQL_DATABASE: 'xxxdb'
volumes:
- ./database:/var/lib/mysql
ports:
- "3306:3306"
这是我加载和转储内容的方式:
import yaml
with open("docker-compose.yml", 'r') as ymlfile:
docker_config = yaml.load(ymlfile)
with open("docker-compose.yml", 'w') as newconf:
yaml.dump(docker_config, newconf)
这就是文件的保存方式。
services:
mysql:
container_name: xxx-mysql
environment: {MYSQL_DATABASE: xxxdb, MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript}
image: mariadb:latest
ports: ['3306:3306']
restart: always
volumes: ['./database:/var/lib/mysql']
web:
build: .
container_name: xxx
depends_on: [mysql]
ports: ['80:80']
volumes: ['.:/xxx']
version: '2'
有什么更好的方法吗?!我错过了什么?
写yaml时需要添加default_flow_style=False
:
import yaml
with open("docker-compose.yml", 'r') as ymlfile:
docker_config = yaml.load(ymlfile)
with open("docker-compose_new.yml", 'w') as newconf:
yaml.dump(docker_config, newconf, default_flow_style=False)
然后您将得到以下输出,除了使用字母顺序书写行外,与您的输入类似:
services:
mysql:
container_name: xxx-mysql
environment:
MYSQL_DATABASE: xxxdb
MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript
image: mariadb:latest
ports:
- 3306:3306
restart: always
volumes:
- ./database:/var/lib/mysql
web:
build: .
container_name: xxx
depends_on:
- mysql
ports:
- 80:80
volumes:
- .:/xxx
version: '2'
请注意,在您原来的 docker-compose.yaml
中,您声明了 ports
变量两次,因此 yaml 解析器只会考虑最后一个变量。要解决此问题,请删除以下行:
ports:
- "3306:3306"
然后,运行 上面解释的写操作给出以下输出:
services:
mysql:
container_name: xxx-mysql
environment:
MYSQL_DATABASE: xxxdb
MYSQL_ROOT_PASSWORD: thiswillbechangeonsetupscript
image: mariadb:latest
ports:
- 32768:32768
- 3306:3306
restart: always
volumes:
- ./database:/var/lib/mysql
web:
build: .
container_name: xxx
depends_on:
- mysql
ports:
- 80:80
volumes:
- .:/xxx
version: '2'
PyYAML 的默认转储是对叶节点使用流样式([....]
用于序列,{...}
用于映射),因此您至少应该指定 yaml.dump(....., default_flow_style=False)
然后 YAML 规范声明不能保证键的顺序,您看到的是 PyYAML 按排序顺序转储它们。
我可以推荐使用 ruamel.yaml
(免责声明:我是那个包的作者),它的具体目标是允许这种往返,与输入相比,变化最小,通常none 完全没有。包括键顺序、流与块样式、字符串引号等。
还有另一个使用 ruamel.yaml
的原因:如果您 运行 输入此程序:
import sys
import ruamel.yaml
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.indent(sequence=3, offset=1)
with open("docker-compose.yml", 'r') as ymlfile:
data = yaml.load(ymlfile)
yaml.dump(data, sys.stdout)
你会得到一个 DuplicateKeyError:
ruamel.yaml.constructor.DuplicateKeyError: while constructing a mapping
in "docker-compose.yml", line 13, column 5
found duplicate key "ports" with value "[]" (original value: "[]")
in "docker-compose.yml", line 24, column 5
因为 ports
在作为键 mysql
的值的映射中作为键出现两次。根据 YAML 规范(PyYAML 停用的旧 1.1 和较新的 1.2),这是不允许的,但 PyYAML 会静默处理第一个键值对,使端口 32768 未映射。
从输入中删除最后两行后,程序的输出为:
version: '2'
services:
web:
container_name: xxx
ports:
- "80:80"
volumes:
- .:/xxx
depends_on:
- mysql
build: .
mysql:
ports:
- "32768:32768"
- "3306:3306"
container_name: xxx-mysql
restart: always
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: 'thiswillbechangeonsetupscript'
MYSQL_DATABASE: 'xxxdb'
volumes:
- ./database:/var/lib/mysql
希望这足以满足您的预期目的。
请注意,PyYAML 删除了 - "80:80"
中的引号,这很好,因为 80:80
不会被错误地解释为六十进制,但是如果您对端口 25 进行更改 - 80:80
- 25:25
在使用像 PyYAML 这样的 YAML 1.1 解析器(如 docker-compose
所做的那样)时与 - "25:25" (the former equalling
- 1525`)
基于此,我制作了一个实用程序 ruamel.dcw
,它使用此功能来预处理 docker 撰写文件,允许环境变量的默认值(如果它们未设置)和其他一些技巧,写出一个临时文件然后调用 docker-compose -f tmpfile
,你应该使用类似的技术,在 运行.