减少自定义SaltStack状态重复:Podman容器应用配置复用方案咨询
针对你遇到的Podman应用状态重复问题,除了参数化状态+Pillar、SaltStack公式、自定义Python模块外,还有以下几个实用方案:
1. 利用include + extend实现基础状态复用
先编写一个包含所有通用步骤的基础状态文件(比如podman_base.sls),然后每个应用的状态文件通过include引入基础逻辑,再用extend覆盖或补充应用特有的配置。
示例:
- 基础状态
podman_base.sls:
# 创建通用用户组 app_group: group.present: - name: appgroup - gid: 1000 # 创建通用用户 app_user: user.present: - name: appuser - gid: 1000 - home: /var/lib/appuser - createhome: True # 创建通用目录结构 app_data_dir: file.directory: - name: /var/lib/appuser/data - user: appuser - group: appgroup - mode: '0750' # 基础systemd单元生成逻辑 podman_systemd_unit: cmd.run: - name: podman generate systemd --new --name {{ container_name }} > /etc/systemd/system/{{ service_name }}.service - unless: test -f /etc/systemd/system/{{ service_name }}.service - require: - user: app_user
- 某个应用的状态
myapp.sls:
# 引入基础状态 include: - podman_base # 覆盖基础状态中的用户配置 extend: app_group: group.present: - name: myappgroup - gid: 1001 app_user: user.present: - name: myappuser - gid: 1001 - home: /var/lib/myappuser app_data_dir: file.directory: - name: /var/lib/myappuser/data podman_systemd_unit: cmd.run: - name: podman generate systemd --new --name myapp_container > /etc/systemd/system/myapp.service - unless: test -f /etc/systemd/system/myapp.service
这种方式无需大量if/else,每个应用只需关注与基础状态的差异部分,可读性强。
2. 封装Jinja2宏实现逻辑复用
把重复的Podman应用配置逻辑封装成Jinja2宏,放在单独的宏文件中(比如macros/podman_app_macros.j2),然后在每个应用的状态文件中调用宏并传入应用专属参数。
示例:
- 宏文件
macros/podman_app_macros.j2:
{% macro setup_podman_app(app_name, app_user, app_gid, data_dir, container_name, service_name) %} # 创建应用用户组 {{ app_name }}_group: group.present: - name: {{ app_user }} - gid: {{ app_gid }} # 创建应用用户 {{ app_name }}_user: user.present: - name: {{ app_user }} - gid: {{ app_gid }} - home: /var/lib/{{ app_user }} - createhome: True # 创建数据目录 {{ app_name }}_data_dir: file.directory: - name: {{ data_dir }} - user: {{ app_user }} - group: {{ app_user }} - mode: '0750' # 生成systemd服务单元 {{ app_name }}_systemd_unit: cmd.run: - name: podman generate systemd --new --name {{ container_name }} > /etc/systemd/system/{{ service_name }}.service - unless: test -f /etc/systemd/system/{{ service_name }}.service - require: - user: {{ app_name }}_user # 重载systemd并启动服务 {{ app_name }}_systemd_reload: cmd.run: - name: systemctl daemon-reload && systemctl enable --now {{ service_name }} - onchanges: - cmd: {{ app_name }}_systemd_unit {% endmacro %}
- 应用状态
myapp.sls:
{% from 'macros/podman_app_macros.j2' import setup_podman_app %} {{ setup_podman_app( app_name='myapp', app_user='myappuser', app_gid=1001, data_dir='/var/lib/myappuser/data', container_name='myapp_container', service_name='myapp' ) }} # 添加应用专属的备份定时器 myapp_backup_timer: file.managed: - name: /etc/systemd/system/myapp-backup.timer - source: salt://myapp/files/myapp-backup.timer - user: root - group: root - mode: '0644' myapp_backup_service: file.managed: - name: /etc/systemd/system/myapp-backup.service - source: salt://myapp/files/myapp-backup.service - user: root - group: root - mode: '0644' myapp_backup_enable: service.running: - name: myapp-backup.timer - enable: True - require: - file: myapp_backup_timer - file: myapp_backup_service
宏的优势在于把通用逻辑完全封装,每个应用的状态文件只需调用宏并传参,简洁且易于维护,完全避免了复杂的条件判断。
3. 用环境分层与文件根目录实现公共逻辑复用
如果你的应用可以按类别或环境(如测试、生产)划分,可以在SaltStack的file_roots中设置公共目录,将Podman通用状态放在公共目录下,每个应用的状态目录引用公共逻辑后再添加专属配置。
示例配置(/etc/salt/master):
file_roots: base: - /srv/salt/base - /srv/salt/podman_common # 公共Podman逻辑目录 prod: - /srv/salt/prod - /srv/salt/podman_common
然后在/srv/salt/podman_common中存放所有通用的Podman状态(用户创建、目录生成、systemd基础配置等),每个应用的状态文件(如/srv/salt/base/apps/myapp.sls)直接include公共目录中的状态,再补充应用专属内容即可。
这种方式适合大规模应用管理,公共逻辑集中维护,应用专属逻辑独立存放,结构清晰。
4. 动态参数传递(无需Pillar)
编写一个通用的Podman应用状态,通过state.apply调用时直接传递参数,而不是依赖Pillar存储配置。
示例:
- 通用状态
podman_app.sls:
# 创建用户组 {{ pillar['app_name'] }}_group: group.present: - name: {{ pillar['app_user'] }} - gid: {{ pillar['app_gid'] }} # 创建用户 {{ pillar['app_name'] }}_user: user.present: - name: {{ pillar['app_user'] }} - gid: {{ pillar['app_gid'] }} - home: /var/lib/{{ pillar['app_user'] }} # 生成systemd单元 {{ pillar['app_name'] }}_systemd: cmd.run: - name: podman generate systemd --new --name {{ pillar['container_name'] }} > /etc/systemd/system/{{ pillar['service_name'] }}.service - unless: test -f /etc/systemd/system/{{ pillar['service_name'] }}.service
- 调用时传递参数:
salt 'minion01' state.apply podman_app pillar='{"app_name": "myapp", "app_user": "myappuser", "app_gid": 1001, "container_name": "myapp_container", "service_name": "myapp"}'
这种方式无需在Pillar中维护大量应用配置,参数动态传递,适合临时部署或批量管理多个相似应用,状态文件中没有复杂的条件判断。
内容的提问来源于stack exchange,提问作者Robert Munteanu

