Distributed James Server — Run with Kubernetes

Deploy Apache James on Kubernetes with Helm chart.

This chart bootstraps a James mail server on a Kubernetes cluster using the Helm package manager.

Before Starting

Before running the Helm chart, James should have particularly accessed to the following external products:

Apache Cassandra
  • You can deploy Cassandra on Kubernetes with a Cassandra chart for testing purpose. However we would recommend running Cassandra on VirtualMachine for better stablilty.

OpenSearch
RabbitMQ
  • RabbitMQ Cluster Operator is a custom Kubernetes resource designed for the lifecycle (creation, upgrade, graceful shutdown) of a RabbitMQ cluster. Using Quickstart setup is enough for James deployment.

Configuration

Helm Configuration

The James helm package take parameters that will configure and determine the behavior of James. There are 2 configuration files:

  • One contains global, non-confidential, configuration: values.yaml

  • The other one contains secrets: secrets.yaml. Values are encrypted with a key stored generated by sops.

You need to pass these 2 files as parameters to the James Helm package. To verify the coherence and avoid errors, the packages can validate the input.

This package contains a default values.yaml file, but that you should override with proper configuration for your deployment (conf.yaml). The file secrets.sample.yaml will show you the possible values of the secrets file. To generate the secrets.yaml file, you will need a plugin for Helm called helm-scecrets.

Usually, you will save those configurations in different repositories, per deployment.

Have a look at values.md and secrets.md in our Chart documents to have more information on the configuration James is using.

You can find our Helm chart for James in here

James Configuration

The configuration files proper to James are stored in the Chart james/configs folder. They are being stored in a ConfigMap and then being mounted in the James pod at /root/conf path.

If you need to change a conf in James, this is where you need to look at.

For now all configuration files are the same for every deployment, except for mailetcontainer.xml that has been excluded (see section below).

You can get the template mailetcontainer.xml in our sample-configuration folder.

The mailetcontainer.xml is the configuration file in James responsible of mail processing and delivery. It can differ greatly from one deployment to another. For that reason, we have excluded it from james/configs folder for the moment. You need to draft your own version of mailetcontainer.xml and add it to james/configs before start deploying Helm chart, as we can’t actually mount a separate file into the same mounting point as the one sued by the ConfigMap on /root/conf path.

However, the next release of Helm should allow to do something about that (hopefully). The helm package will be updated then.

Deploy James Helm chart

Verify the configuration

We recommend to verify the configuration against the James Helm packages before deploying it. Usually it is best to have to position yourself in the repository having your deployment’s values and secrets, and linking this helm package to it, like this:

$ helm lint -f james/conf.yaml -f james/secrets.yaml /path/to/helm/james

You can also generate the whole templates with values (can be useful for debugging sometimes), by typing:

$ helm secrets templates -f james/conf.yaml -f james/secrets.yaml james /path/to/helm/james

From there, you should be able to interact with the Kubernetes cluster with kubectl command.

A few useful commands:

kubectl get namespace # show namespaces on your cluster

kubectl get pod -n mail-server # list pods running in mail-server namespace

kubectl config set-context --current --namespace=mail-server # set the namespace mail-server as default one for next commands

kubectl get configmaps # list configmaps depoyed on the namespace

kubectl get secrets # list secrets deployed on the namespace

kubectl get service # list services deployed in the namespace

kubectl get nodes -o wide # list nodes related to the namespace

kubectl describe pod my-pod # get a detailed description of my-pod (similar for other objects)

kubectl scale --replicas=4 deployment james # scale up (or down) james to 4 pods

kubectl rollout restart deployment james # force a rollout restart of your pods related to james

kubectl logs my-pod -f --tail 100 # show and follow logs of a pod from the last 100 lines

kubectl logs -f -l app=james --tail 100 # show and follow the combined logs of all james pods from the last 100 lines

kubectl port-forward pod/my-pod 3000:3000 # allow you to access and interact with internal port 3000 of my-pod from localhost

Usually you have a namespace per deployment. Always target your deployments on the corresponding namespace, by either adding the flag -n mail-server on your kubectl and helm commands, or by setting your namespace by default (see in the above commands).

Deploy James Chart

Before doing a real deployment, you need to check that you have at least all necessary values for James to start and run smoothly on your environment. You can check the checklist.md in our document folder for this.

Run the command when you think you are good to go:

$ helm secrets install james james/ -f james/values.yaml -f james/secrets.yaml
Distributed Apache James in Kubernetes

You can also wait for the deployment to be complete by adding a --wait flag, that is based on the readiness probe located inside the James pod.

However sometimes things might not always go well at the start of James. Usually it is good to look at the logs. If it goes without issues until you start to see some successful health check logs, then you are likely good.

Upgrade Chart version

If you want to deploy a new version of a installed package, use helm secrets upgrade:

$ helm secrets upgrade -f james/conf.yaml -f james/secrets.yaml james /path/to/helm/james

What Helm does is that it compares all the generated YAML files with those on the server. And it updates only those that changed. There are however some limitations:

  • pods in errors are not recreated during an upgrade. It allows to check the logs first. However, if you delete the pod by hand, it will be recreated from the last definition.

  • Some artifacts, such as jobs and stateful sets, have immutable properties. So, some upgrades may fail. Deleting by hand the element is sometimes a solution before doing the upgrade.

Install helm-diff plugin to display the changed configurations before run upgrade.
$ helm secrets diff upgrade -f james/conf.yaml -f james/secrets.yaml james /path/to/helm/james

Rollback to previous Chart version

Show chart revision history:

$  helm history james -n <name space>

Rollback to a previous version:

$  helm rollbaack james <revision>

Uninstalling

To uninstall the helm package:

$ helm uninstall james -n <name space>