Hello, World

This section will guide you through the process of initialising an empty Charm template (which defaults to creating a Kubernetes charm), and explain the purpose of each file.


The Charmcraft tool is used throughout the Charm development process, from initialising early directory structure to publishing your finished Charm to Charmhub.

To get started, first ensure that you have an appropriate Development Environment for a Charmed Operator, then create a new Charm named hello-operator, generating the template in its own directory:

# Create the Charm directory
$ mkdir hello-operator; cd hello-operator
# Initialise the Charm directory
$ charmcraft init

This will create a skeleton directory structure, described below:

# Documentation
├── README.md            # The front page documentation for your charm
├── LICENSE              # Your Charm's license (we recommend Apache 2)
# Charm specification and requirements
├── metadata.yaml        # Charmed Operator package description and metadata
├── requirements.txt     # PyPI requirements for the charm runtime environment
# Runtime features
├── config.yaml          # Configuration schema for your operator
├── actions.yaml         # Day 2 action declarations, e.g. backup, restore
# Development files
├── requirements-dev.txt # PyPI requirements for development environment
├── run_tests            # Bash script to run Charm tests
# Charm code and tests
├── src                  # Top-level source code directory for Charm
│ └── charm.py           # Minimal operator using Charmed Operator Framework
└── tests # Top-level directory for Charm tests
├── __init__.py
└── test_charm.py        # Skeleton unit tests for generated charm

The metadata.yaml file is critical, and has a detailed spec that enables you to specify where your Charm should run, how it communicates with other Charms using relations, and any Resources it depends on. We’ll cover these concepts in greater detail later in the docs.

In most Charms, the majority of the operator code is likely to live in src/charm.py, and it is the default entrypoint for the Charm.

Deploy the charm

Before completing this section, ensure you’ve bootstrapped a Juju controller as described in the Development Setup section.

We can now build and deploy our (very minimal!) Charm. Before we do that, let’s configure the Juju model to display DEBUG level log messages and watch the output. Open another terminal and run the following:

# Set the default log level to DEBUG
$ juju model-config logging-config="<root>=WARNING;unit=DEBUG"
# Tail the Juju log
$ juju debug-log

Now, back to our original terminal:

# Build the Charm package (outputs ./hello-operator.charm)
$ charmcraft pack
# Deploy the packaged Charm
$ juju deploy ./hello-operator.charm --resource httpbin-image=kennethreitz/httpbin
# Watch the Juju status to see the Charm's progress
$ watch -c juju status --color

We have to specify the httpbin-image resource to tell Juju which OCI image to deploy for the default container in the template. When your charms are published, this is no longer necessary because the OCI image resource is attached to the charm when you release it. Read more in Publishing and Resources.

The deployment will take about 30 seconds, and you should see the various operator events being triggered in the juju debug-log output. If all goes well, you should see output similar to the following from watch -c juju status --color:

Model        Controller  Cloud/Region        Version  SLA          Timestamp
development  micro       microk8s/localhost  2.9.0    unsupported  10:25:35+01:00

App             Version  Status  Scale  Charm           Store  Channel  Rev  OS          Address  Message
hello-operator           active      1  hello-operator  local             0  kubernetes           

Unit               Workload  Agent  Address       Ports  Message
hello-operator/0*  active    idle                

Note that you can inspect the content of your Charm easily - the bundle is just a zip file! Go ahead and open up hello-operator.charm in your native archive viewer to see how the Charm gets packaged up.

Now the charm is deployed, you should be able to browse to the Pod IP (if you’re using MicroK8s) and see the httpbin user interface. You can confirm it’s working with:

# curl the pod ip (using the example above)
$ curl

Cleaning Up

Now you’ve deployed your charm, you might want to clear up your cluster and remove what we’ve done. You have a few options:

# ⚠ Destroy the model, removing the application and machines with it
$ juju destroy-model --force --no-wait development
# ⚠ Destroy the controller, and also any associated models and deployed applications
# ⚠ Note that you will need to bootstrap again before using Juju on the cluster
$ juju kill-controller -y -t0 micro

Following the previous pages I installed charmcraft edge and juju 2.9 candidate.

Deploying with juju deploy ./hello-operator.charm errors out:

ERROR series with metadata v2 not valid

So I replaced

series: [kubernetes]


  - kubernetes

The next issue is that the output of charmcraft init is not deployable:

ERROR invalid charm "hello-operator": has no hooks nor dispatch file


Thanks! I think this is due to some recent changes in Charmcraft. I’m working on a pull request that will change the default init template that I hope to get merged early next week. Will investigate and update the docs!

Hey Jon,

As I’m walking through this doc, I found that there’s an implied step missing.

Between the charmcraft init and the charmcraft pack, there should be instructions to enter the created directory, which kind of seems implied by the “This will create a skeleton directory structure” section, but may confuse a new charmcraft user.

Also, I’m getting the following on my charmcraft init and pack commands when running on Ubuntu 21.04:

update.go:85: cannot change mount namespace according to change mount (/run/user/1000/doc/by-app/snap.charmcraft /run/user/1000/doc none bind,rw,x-snapd.ignore-missing 0 0): cannot inspect "/run/user/1000/doc": lstat /run/user/1000/doc: permission denied


Thanks, I’ve updated the doc slightly to a more simple alternative.

As for that error, I’m not sure. Looks like a snapd problem on the machine rather than charmcraft specifically. What version of charmcraft is installed?

Thanks, Jon.

Here’s my charmcraft version:
charmcraft 1.0.0 403 latest/beta canonical* -

Running snapd-2.49.2+21.04ubuntu1.

I’ll try a dist-upgrade and reboot later along with a re-install of charmcraft to see if it clears my local error.

I determined that it was my shell in which I had run “newgrp microk8s” (while following the development quick start guide) that was causing this interaction with snapd confinement.

1 Like

Interesting! Thanks for the update.

Hi, here are some suggestions that might improve this page.

Two points I think are missing are:

  1. This will produce a k8s charm
  2. How do you bootstrap? Maybe we should link to Juju | Development Setup on this subject.

I’ll mention that the template will produce a Kubernetes charm, though my assumption is that people follow the development setup guide before Hello, World, and thus will already be bootstrapped. I can add a link either way…

Thanks :slight_smile:

1 Like

In the section “Deploy the charm”, it’s mention to use command juju debug-log to get the output of the operators status

Model        Controller  Cloud/Region        Version  SLA          Timestamp
development  micro       microk8s/localhost  2.9.0    unsupported  10:25:35+01:00

App             Version  Status  Scale  Charm           Store  Channel  Rev  OS          Address  Message
hello-operator           active      1  hello-operator  local             0  kubernetes           

Unit               Workload  Agent  Address       Ports  Message
hello-operator/0*  active    idle                

I think the correct command to get the output should be watch -c juju status --color

1 Like