一键导入
charmcraft
Expert guidance for developing, building, testing, and publishing Juju charms using charmcraft
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Expert guidance for developing, building, testing, and publishing Juju charms using charmcraft
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Known-good Juju bundle shapes (COS Lite, 12-Factor + COS, Identity Platform, Charmed Kubeflow) — canonical app lists and relation edges
Implementing Juju actions for operational tasks in charms. WHEN: add Juju actions to a charm, implement backup / rotate-credentials / restore actions, declare actions in charmcraft.yaml, write action handlers, test actions with Scenario, run actions with juju run.
Adding and validating charm configuration options. WHEN: add charm configuration options, declare config in charmcraft.yaml, validate config values in config-changed, apply config to a Pebble layer, apply config to a machine charm, write Scenario tests for config.
End-to-end workflow for building ops-framework charms for custom applications (K8s and machine). WHEN: build a custom Juju charm, write src/charm.py with Pebble, write a machine charm with systemd, decide K8s vs machine substrate, scaffold a non-paas-charm with charmcraft init, customise the ops framework charm lifecycle.
Workflow for charming infrastructure software (databases, caches, message brokers, proxies, monitoring). WHEN: charm infrastructure software, charm a database / cache / message broker / proxy / monitoring system, implement peer relations, leader election, primary/replica failover, backup and restore actions, clustering.
Expert guidance for developing, building, testing, and publishing Juju charms using charmcraft. WHEN: edit charmcraft.yaml, run charmcraft pack, run charmcraft init, manage charm libraries, publish a charm to Charmhub, set up multi-base builds, configure relations / config options, set up storage or containers.
| name | charmcraft |
| description | Expert guidance for developing, building, testing, and publishing Juju charms using charmcraft |
Expert guidance for developing, building, testing, and publishing Juju charms using charmcraft.
# Initialise new charm with profile
charmcraft init --profile=kubernetes # K8s charm (default)
charmcraft init --profile=machine # Machine charm
charmcraft init --profile=flask-framework # Flask 12-factor (stable)
charmcraft init --profile=django-framework # Django 12-factor (stable)
charmcraft init --profile=fastapi-framework # FastAPI 12-factor (experimental)
charmcraft init --profile=go-framework # Go 12-factor (experimental)
charmcraft init --profile=express-framework # ExpressJS 12-factor (experimental)
charmcraft init --profile=spring-boot-framework # Spring Boot 12-factor (experimental)
# Experimental profiles need:
# CHARMCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=true charmcraft init …
# CHARMCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=true charmcraft pack
# Cantrip's `charmcraft_init` tool sets the flag automatically for the
# four experimental profiles.
# With custom name and author
charmcraft init --name=my-charm --author="Your Name"
# List/expand extensions
charmcraft list-extensions
charmcraft expand-extensions
If the directory is not empty (for example, there is a plan, AGENTS.md, or a .git folder), you need to add --force.
After init:
charmcraft.yaml (metadata, bases, relations, config)README.md (becomes Charmhub documentation)src/charm.py (using Ops framework). Charmcraft 4.2's
kubernetes and machine profiles scaffold a src/workload.py
module alongside the charm so workload-specific logic stays out of
src/charm.py. Keep this split when you grow the charm — the
charm class wires Juju events; the workload module talks to the
process or container.tests/unit/ and tests/integration/. Templates
now use pytest-jubilant for integration tests out of the box (see
the jubilant-tests skill).# Build charm
charmcraft pack # Main command
charmcraft pack -o ./build/ # Custom output directory
charmcraft pack --bases-index=0 # Specific base (if multiple defined)
# Analyse charm (always run before uploading!)
charmcraft analyse ./my-charm_ubuntu-22.04-amd64.charm
charmcraft analyse --format=json ./my-charm.charm
# Clean build artefacts
charmcraft clean
# Remote build (for multi-architecture)
charmcraft remote-build
Build lifecycle: pack handles everything automatically. Only use individual steps (pull, build, stage, prime) for debugging.
Always run charmcraft analyse before uploading to catch:
# Run tests
charmcraft test # Integration tests
charmcraft test --shell # Debug environment
charmcraft test --debug # Shell on failure
# Local quality checks
tox -e format # Format with ruff
tox -e lint # Lint with ruff + pyright
tox -e unit # Unit tests (ops.testing)
tox -e integration # Integration tests
# Account setup
charmcraft login
charmcraft whoami
charmcraft register my-charm # Register name first
# Upload and release
charmcraft upload ./my-charm.charm --release=edge
charmcraft status my-charm # Check status
charmcraft revisions my-charm # List revisions
# Release specific revision
charmcraft release my-charm --revision=5 --channel=stable
# Promote between channels
charmcraft promote my-charm --from=beta --to=stable
# Close channel
charmcraft close my-charm edge
Channel structure: [track/]risk[/branch]
edge -> beta -> candidate -> stablestable, edge, 2.0/candidate, beta/hotfix-123Always: Upload to edge first, test thoroughly, then promote through channels.
# Manage resources (images, binaries)
charmcraft resources my-charm
charmcraft upload-resource my-charm my-resource --filepath=./file.tar.gz
charmcraft resource-revisions my-charm my-resource
# Release with specific resources
charmcraft release my-charm --revision=5 --channel=stable --resource=my-resource:3
# Using libraries (define in charmcraft.yaml first)
charmcraft fetch-libs # Fetch defined libraries
charmcraft list-lib postgresql # List available libs
# Publishing libraries
charmcraft create-lib my-charm my_library
charmcraft publish-lib charms.my_charm.v0.my_library
In charmcraft.yaml:
charm-libs:
- lib: postgresql.postgres_client
version: "0" # Major version (auto-updates minor)
- lib: mysql.client
version: "0.57" # Pinned version
Library versioning:
v0, v1 = breaking changes (API changes)lib/charms/{charm_name}/v{X}/{lib_name}.pycharmlibs-*)A growing subset of the ecosystem has been lifted into the
canonical/charmlibs monorepo and is published to PyPI. Prefer the
PyPI package — it's versioned, hash-pinnable, and avoids a charmcraft fetch-libs step. The import path changes from charms.foo.vN.bar
to charmlibs.bar (or charmlibs.interfaces.bar).
| PyPI package | Import | Replaces |
|---|---|---|
charmlibs-pathops | from charmlibs import pathops | — (new; pathlib-style API for Pebble containers + local filesystem) |
charmlibs-apt | from charmlibs import apt | charms.operator_libs_linux.v0.apt |
charmlibs-snap | from charmlibs import snap | charms.operator_libs_linux.v*.snap |
charmlibs-passwd | from charmlibs import passwd | charms.operator_libs_linux.v*.passwd |
charmlibs-sysctl | from charmlibs import sysctl | charms.operator_libs_linux.v*.sysctl |
charmlibs-systemd | from charmlibs import systemd | charms.operator_libs_linux.v*.systemd |
charmlibs-nginx-k8s | from charmlibs import nginx_k8s | Charm-side nginx helpers |
charmlibs-interfaces-tls-certificates | from charmlibs.interfaces import tls_certificates | charms.tls_certificates_interface.v* |
charmlibs-interfaces-certificate-transfer | from charmlibs.interfaces import certificate_transfer | charms.certificate_transfer_interface.v* |
charmlibs-interfaces-otlp | from charmlibs.interfaces import otlp | interface schema only |
charmlibs-interfaces-mcp | from charmlibs.interfaces import mcp | interface schema only |
charmlibs-interfaces-sloth | from charmlibs.interfaces import sloth | interface schema only |
charmlibs-interfaces-k8s-backup-target | from charmlibs.interfaces import k8s_backup_target | interface schema only |
charmlibs-interfaces-gateway-metadata | from charmlibs.interfaces import gateway_metadata | interface schema only |
cosl | import cosl | COS Lite utilities (topology labels, Loki logging handler, cos-tool bindings) |
Install with uv:
uv add charmlibs-pathops
uv add charmlibs-apt charmlibs-snap # just the submodules you need
charmcraft fetch-libsThese charm libraries are not on PyPI yet and must be fetched the classic way:
charms.loki_k8s.* — log-forwarder librarycharms.grafana_k8s.* — dashboard providercharms.prometheus_k8s.* — scrape librarycharms.traefik_k8s.* — ingress requirercharms.tempo_k8s.*, charms.tempo_coordinator_k8s.*charms.catalogue_k8s.*charms.observability_libs.*charms.data_platform_libs.* (Juju data-platform relation interfaces — PyPI namespace dpcharmlibs is reserved but not yet populated)charms.sdcore_nms_k8s.*charms.hydra.* — Canonical Identity Platform OAuth / OIDC requirer libs (oauth, oauth_cli, oidc_info, token_introspect); load the identity-platform skill when wiring thesecharms.kratos.* — Kratos identity / external-IdP libs (kratos_external_idp, kratos_info); load the identity-platform skill when wiring thesecharms.vault_kv.* etc.) — check their host charm before assuming# Required fields
name: string # Charm name (lowercase, hyphens, no spaces)
type: charm | bundle # Always "charm"
# Recommended fields
title: string # Human-readable title
summary: string # Short description (< 100 chars)
description: | # Full description (supports markdown)
Multi-line description of your charm.
# Base configuration (Charmcraft 4.2 form — preferred)
base: ubuntu@24.04
build-base: ubuntu@24.04
platforms:
amd64:
arm64: # Optional — list each platform you build for.
# Declare runtime expectations. K8s charms on Charmcraft 4.2 should
# include both juju >= 3.6 and k8s-api so deployment fails fast on
# incompatible controllers.
assumes:
- juju >= 3.6
- k8s-api # Drop this line for machine charms.
# Build configuration (required)
parts:
charm:
plugin: uv
source: .
build-snaps:
- astral-uv
# Optional but recommended
extensions: [] # List of extensions to use
charm-libs: [] # Library dependencies
links: # Links shown on Charmhub
documentation: https://discourse.charmhub.io/...
issues: https://github.com/...
source: https://github.com/...
website: https://...
config:
options:
port:
type: int
description: "Port to listen on"
default: 8080
enable-tls:
type: boolean
description: "Enable TLS/SSL"
default: false
server-name:
type: string
description: "Server hostname"
default: "localhost"
Types: string, int, float, boolean, secret
actions:
backup:
description: "Create a backup"
params:
destination:
type: string
description: "Backup destination path"
required: [destination]
additionalProperties: false
Always include additionalProperties: false in action definitions.
provides:
website:
interface: http
requires:
database:
interface: postgresql
optional: true
ingress:
interface: ingress
optional: true
limit: 1
peers:
cluster:
interface: cluster
ALWAYS include optional: true or optional: false for requires relations — never rely on the default.
containers:
my-app:
resource: my-image
mounts:
- storage: data
location: /data
resources:
my-image:
type: oci-image
description: "Application image"
storage:
data:
type: filesystem
description: "Application data"
location: /var/lib/myapp
minimum-size: 1G
K8s charms support a single instance of each declared storage; machine charms get a list. Read events with bracket notation, never attribute notation:
self.framework.observe(
self.on["data"].storage_attached, # bracket notation
self._on_data_attached,
)
In the handler, resolve the workload mount from charmcraft metadata:
mount = self.meta.containers["my-app"].mounts["data"].location
For K8s charms there is exactly one storage instance, so index [0]:
storage = self.model.storages["data"][0]
Consider the pathops library (on PyPI) when you need pathlib-style
file operations against the workload container.
To target multiple bases, declare a platforms entry per base/arch and
pack each separately. Charmcraft 4.2 retired the build-on/run-on
matrix; use one charmcraft.yaml per base or override at pack time:
charmcraft pack --base=ubuntu@24.04
charmcraft pack --base=ubuntu@22.04
When picking values for the assumes: block, line up with the version
matrix the upstream operator docs publish:
| Juju | Pebble | Notes |
|---|---|---|
| 3.6 | 1.19.2 | LTS — safe minimum for Charmcraft 4.2. |
| 4.0 | 1.26.0 | Required for newer Pebble notice / check kinds. |
Bump the floor only when the charm actually uses a feature that needs it.
# In charmcraft.yaml
requires:
database:
interface: postgresql_client
optional: true
charm-libs:
- lib: data_platform_libs.data_interfaces
version: "0"
# In src/charm.py
from charms.data_platform_libs.v0.data_interfaces import DatabaseRequires
class MyCharm(CharmBase):
def __init__(self, *args):
super().__init__(*args)
self.database = DatabaseRequires(self, "database", "myapp")
self.framework.observe(
self.database.on.database_created,
self._on_database_created
)
tox -e lint and tox -e format frequentlycharmcraft analyse on every buildcharmcraft pack then juju deploy ./my-charm.charmCommit: charmcraft.yaml, all source, uv.lock, pyproject.toml, tests, docs
Ignore: *.charm, __pycache__/, .tox/, venv/, .claude/settings.local.json
Build fails:
charmcraft.yaml syntaxsrc/charm.py, uv.lock)charmcraft -v pack for verbose outputUpload fails:
charmcraft logincharmcraft register my-charmcharmcraft analyse ./my-charm.charmLibrary errors:
charmcraft fetch-libscharmcraft.yamlRuntime issues:
juju debug-logcharmcraft resources my-charmChanges not reflected in charm:
charmcraft clean && charmcraft packjuju refresh my-charm --path=./my-charm.charm# Setup
charmcraft init --profile=kubernetes
charmcraft login
# Development cycle
charmcraft pack
charmcraft analyse ./my-charm.charm
tox -e lint
tox -e unit
# Publishing
charmcraft upload ./my-charm.charm --release=edge
charmcraft status my-charm
charmcraft promote my-charm --from=edge --to=beta
# Libraries
charmcraft fetch-libs
charmcraft publish-lib charms.my_charm.v0.my_library
# Testing with Juju
juju deploy ./my-charm.charm
juju status
juju debug-log