使用 PyYAML 编辑 docker-compose.yml

Leo*_*ani 4 python pyyaml docker docker-compose

我有一个非常标准的 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"
Run Code Online (Sandbox Code Playgroud)

这就是我加载和转储内容的方式:

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)
Run Code Online (Sandbox Code Playgroud)

这就是文件的保存方式。

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'
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法来做到这一点?!我缺少什么?

Ant*_*hon 6

PyYAML 的默认转储是对叶节点使用流样式([....]对于序列、{...}对于映射),因此您至少应该指定yaml.dump(....., default_flow_style=False)

然后 YAML 规范声明不保证键的顺序,您看到的是 PyYAML 按排序顺序转储它们。

我可以推荐使用ruamel.yaml(免责声明:我是该包的作者),它的具体目标是允许这种往返,与输入相比,变化最小,通常根本没有变化。包括键排序、流与块样式、字符串引号等。

使用 的还有另一个原因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)
Run Code Online (Sandbox Code Playgroud)

你会得到一个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
Run Code Online (Sandbox Code Playgroud)

因为ports在映射中作为 key 出现两次,即 key 的值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
Run Code Online (Sandbox Code Playgroud)

希望这足够接近您的预期目的。

请注意,PyYAML 删除了 中的引号- "80:80",这很好,因为80:80不能被错误地解释为六十进制,但是如果您对端口 25 进行某些操作,则- 80:80- 25:25使用像 PyYAML 这样的 YAML 1.1 解析器(就像- 1525docker-compose一样)时,会有很大不同。 - "25:25" (the former equalling

基于此,我制作了一个实用程序ruamel.dcw,它使用此功能来预处理 docker compose 文件,允许环境变量的默认值(如果未设置)和一些其他技巧,写出一个临时文件,然后调用docker-compose -f tmpfile,您应该使用类似的技术,在运行后处理临时文件。


Moh*_*OUI 5

default_flow_style=False写yaml的时候需要加上:

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)
Run Code Online (Sandbox Code Playgroud)

然后,您将获得以下输出,除了使用字母顺序编写行外,与您的输入类似:

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'
Run Code Online (Sandbox Code Playgroud)

请注意,在您的原始文件中,docker-compose.yaml您声明了ports两次变量,因此 yaml 解析器只会考虑最后一个变量。要解决此问题,请删除以下行:

ports:
  - "3306:3306"
Run Code Online (Sandbox Code Playgroud)

然后,按照上面的解释运行写操作会得到以下输出:

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'
Run Code Online (Sandbox Code Playgroud)