繁体   English   中英

使用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'

有什么更好的方法吗? 我想念的是什么?

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

然后,YAML规范指出不能保证键的顺序,而您看到的是PyYAML以排序顺序转储它们。

我可以建议使用ruamel.yaml (免责声明:我是该程序包的作者),该程序的特定目标是允许这种往返操作与输入相比具有最小的变化,而根本没有变化。 包括键顺序,流vs块样式,字符串引号等。

使用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不能被错误地解释为60进制,但如果你用25端口变化的东西- 80:80- 25:25也是千差万别使用像PyYAML这样的YAML 1.1解析器时(与docker-compose一样)与- "25:25" (the former equalling -1525`)不同

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

编写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'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM