Using the operator
Contents
This section covers the operator functionality and how to use it, once installed on a Kubernetes cluster.
Custom Resources
The operator introduces a couple of new resources into your Kubernetes cluster.
Xp7Deployment
This is the main custom resource that defines your deployment. It is namespaced, so you have to create a namespace for it. Only 1 Xp7Deployment can reside in each namespace.
apiVersion: enonic.cloud/v1
kind: Xp7Deployment
metadata:
name: my-deployment
namespace: my-namespace
spec:
enabled: true # Should the pods be running
xpVersion: 7.13.2 # XP version, must be >=7.13.2
# List of disks shared by all nodes (see description of disks below)
nodesSharedDisks:
- name: blobstore
size: 1Gi
- name: snapshots
size: 1Gi
- name: export
size: 1Gi
# List of nodegroups
nodeGroups:
# Name and number of replicas
- name: main
replicas: 1
# Role of the node
data: true
master: true
initContainers:
# Preinstall Snapshotter app
- image: enonic/snapshotter:3.1.0
name: snapshotter-deploy
mounts:
- name: deploy
mountPath: /deploy
# Environment variables
env:
- name: MY_ENV_VAR
value: hey
resources:
# Cpu and memory allocation
cpu: "1.5"
memory: 512Mi
dirs:
# Snapshotter app copied to deploy folder
- name: deploy
size: 100Mi
mountReadOnly: true
# List of disks private to each and every node
disks:
- name: deploy
size: 1Gi
- name: index
size: 1Gi
- name: work
size: 1Gi
Disks
In the Xp7Deployment resource we have names of disks that you can define to be shared, private or non existant.
- blobstore
-
All blob objects. This should always be shared in a cluster.
- snapshots
-
Index snapshots. This should always be shared in a cluster.
- export
-
Data dumps and other data. This should be shared in a cluster.
- index
-
Private node index. This should never be shared.
- work
-
Private node cache. This should never be shared.
- deploy
-
Locally installed apps on this single node. This should never be shared.
Xp7Config
This custom resource manages the configuration of XP nodes. This resource namespaced, and should be created in a namespace that already contains a Xp7Deployment.
apiVersion: enonic.cloud/v1
kind: Xp7Config
metadata:
name: my-config
namespace: my-namespace
spec:
#nodeGroup: all
#dataBase64: false
file: my.app.name.cfg
data: |
my = custom
config = file
The nodegroup field is optional and defaults to all nodegroups. If you want to apply you configuration only to a single node group, set the field appropriately. |
The dataBase64 field is optional and defaults to false . |
You can also create Xp7Config files that hold binary data. To do that you have to base64 encode the data and set the dataBase64
field to true like so:
apiVersion: enonic.cloud/v1
kind: Xp7Config
metadata:
name: my-config
namespace: my-namespace
spec:
#nodeGroup: all
dataBase64: true
file: my.app.name.cfg
data: SGVpISBZb3UgYXJlIG9uZSBub3N5IGZveC4gVGhpcyBpcyB0b3Agc2VjcmV0IGRhdGEuIEdldCBvdXQgb2YgaGVyZS4gU2hvb28uLi4uLi4uLi4uLg==
It can vary how fast XP registers the Xp7Config changes. It can be instant, but it can also take up to a couple of minutes, depending on the Kubernetes cluster setup. |
Xp7App
This resource is to manage apps with the operator. While you can manage them with XP, this provides you with the option to create a deployment complete with your custom apps using the operator. This resource namespaced, and should be created in a namespace that already contains a Xp7Deployment.
apiVersion: enonic.cloud/v1
kind: Xp7App
metadata:
name: contentstudio
namespace: my-namespace
spec:
url: https://repo.enonic.com/public/com/enonic/app/contentstudio/5.0.3/contentstudio-5.0.3.jar
#sha512: ba6b40ebf0808c6fa619ba2a05d07ce3e566eada7e9f3f34c1d280e9d1dcbd1e3c25eff9896d1057c4578ff3f516afa7a905c9e42ddc5e08f1cdf06f7e89774c
The sha512 field is optional, but if provided, XP will validate the sha512 sum of the jar before installing it. This prevents installing of potential malicious apps from the internet. |
Added functionality
In addition to new resources, there are also new annotations that add some functionality.
Ingresses
To create virtual hosts for XP you use ingress annotations. These follow the format of:
enonic.cloud/xp7.vhost.mapping.<MAPPING_NAME>.source: /admin
enonic.cloud/xp7.vhost.mapping.<MAPPING_NAME>.target: /admin
enonic.cloud/xp7.vhost.mapping.<MAPPING_NAME>.idproviders: <DEFAULT_IDPROVIDER>,<OTHER_ENABLED_IDPROVIDER>
A very important thing to keep in mind is that the annotation enonic.cloud/xp7.vhost.mapping.<MAPPING_NAME>.source
has to match a defined spec.rules[?].http.paths[?].path
in the same ingress. That is so the operator knows what node groups it needs to update. That brings us to the second point. The spec.rules[?].http.paths[?].backend.serviceName
has to match a node group name defined in your Xp7Deployment.
An example of a valid ingress, assuming you have a nodegroup main
, would look something like this.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-domain-com
namespace: my-namespace
annotations:
enonic.cloud/xp7.vhost.mapping.my-mapping-site.source: /
enonic.cloud/xp7.vhost.mapping.my-mapping-site.target: /site/default/master/homepage
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.source: /admin
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.target: /admin
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.idproviders: system
spec:
rules:
- host: my-domain.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: main
port:
number: 8080
- path: /admin
pathType: ImplementationSpecific
backend:
service:
name: main
port:
number: 8080
Like Xp7Config, changes to virtual hosts can take a couple of minutes to register in XP. |
Namespaces
It can be desireble to delete all created resources that are associated with an Xp7Deployment once its deleted. That is quite easy to do with this namespace annotation:
apiVersion: v1
kind: Namespace
metadata:
name: my-namespace
annotations:
enonic.cloud/remove.with.xp7deployment: my-deployment
Common operations
Get deployment status
$ kubectl -n my-namespace get xp7deployments.enonic.cloud
NAME ENABLED VERSION STATE MSG
my-deployment true 7.13.2 RUNNING OK
Get config status
$ kubectl -n my-namespace get xp7configs.enonic.cloud
NAME NODEGROUP FILE STATE MSG
all-admin all com.enonic.xp.app.main.cfg READY OK
all-appstatus all com.enonic.app.status.cfg READY OK
all-cluster all com.enonic.xp.cluster.cfg READY OK
all-logback all logback.xml READY OK
all-sessionstore all com.enonic.xp.web.sessionstore.cfg READY OK
all-system all system.properties READY OK
main-elasticsearch main com.enonic.xp.elasticsearch.cfg READY OK
main-vhosts main com.enonic.xp.web.vhost.cfg READY OK
my-config all com.my-app.cfg READY OK
Get app status
$ kubectl -n my-namespace get xp7apps.enonic.cloud
NAME KEY VERSION STATE MSG
contentstudio com.enonic.app.contentstudio 3.2.0 RUNNING OK
Fetching SU password
$ kubectl -n my-namespace get secret su -o go-template="{{ .data.pass | base64decode }}"
NGDDlGdFYkX8i@#49#Z6N45tfhX6#3Rw
Access admin (bypassing ingress)
$ kubectl -n my-namespace port-forward main-0 8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Then open up localhost:8080 in your browser.
View XP logs
$ kubectl -n my-namespace logs -c exp main-0
_____
____________________________(_)______ ____ _________
_ _ \_ __ \ __ \_ __ \_ /_ ___/ __ |/_/__ __ \
/ __/ / / / /_/ / / / / / / /__ __> < __ /_/ /
\___//_/ /_/\____//_/ /_//_/ \___/ /_/|_| _ .___/
/_/
# Enonic XP 7.13.2
# Built on 2021-02-02T15:28:02Z (hash = 632195fda1bf0e9ce4a314d70b403ef731955ad0, branch = e4ea190187bd27bc1143a29c4ff2c80e564f58c0)
# OpenJDK 64-Bit Server VM 11.0.10 (AdoptOpenJDK)
# Linux 4.19.157 (amd64)
# Install directory is /enonic-xp
# Home directory is /enonic-xp/home
....
Edit configuration
$ kubectl -n my-namespace edit xp7configs.enonic.cloud my-config
xp7config.enonic.cloud/my-config edited
Watch configuration
$ kubectl -n my-namespace get xp7configs.enonic.cloud -w
NAME NODEGROUP FILE STATE MSG
all-admin all com.enonic.xp.app.main.cfg READY OK
all-appstatus all com.enonic.app.status.cfg READY OK
all-cluster all com.enonic.xp.cluster.cfg READY OK
all-logback all logback.xml READY OK
all-sessionstore all com.enonic.xp.web.sessionstore.cfg READY OK
all-system all system.properties READY OK
main-elasticsearch main com.enonic.xp.elasticsearch.cfg READY OK
main-vhosts main com.enonic.xp.web.vhost.cfg READY OK
my-config all com.my-app.cfg PENDING Not loaded
Simple example
Let’s deploy a simple example. Create a file called simple.yaml
and paste these contents to it:
# Create a namespace
apiVersion: v1
kind: Namespace
metadata:
name: my-namespace
annotations:
# Delete this namespace if the deployment is deleted
enonic.cloud/remove.with.xp7deployment: my-deployment
---
# Create deployment in the namespace
apiVersion: enonic.cloud/v1
kind: Xp7Deployment
metadata:
name: my-deployment
namespace: my-namespace
spec:
enabled: true
xpVersion: 7.13.2
# Create one node
nodeGroups:
- name: main
replicas: 1
data: true
master: true
initContainers:
# Preinstall Snapshotter app
- image: enonic/snapshotter:3.1.0
name: snapshotter-deploy
mounts:
- name: deploy
mountPath: /deploy
resources:
cpu: "1"
memory: 512Mi
dirs:
# Snapshotter app copied to deploy folder
- name: deploy
size: 100Mi
mountReadOnly: true
# Volumes private to the node
disks:
- name: blobstore
size: 1Gi
- name: snapshots
size: 1Gi
- name: export # Dumps and other data
size: 1Gi
- name: index # Node ES index
size: 1Gi
- name: work # Node cache
size: 1Gi
---
# Install content studio
apiVersion: enonic.cloud/v1
kind: Xp7App
metadata:
name: contentstudio
namespace: my-namespace
spec:
url: https://repo.enonic.com/public/com/enonic/app/contentstudio/5.0.3/contentstudio-5.0.3.jar
sha512: ba6b40ebf0808c6fa619ba2a05d07ce3e566eada7e9f3f34c1d280e9d1dcbd1e3c25eff9896d1057c4578ff3f516afa7a905c9e42ddc5e08f1cdf06f7e89774c
---
# Add your own custom config
apiVersion: enonic.cloud/v1
kind: Xp7Config
metadata:
name: my-config
namespace: my-namespace
spec:
nodeGroup: all
file: com.my-app.cfg
data: |
my = config
---
# Expose XP through an ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-domain-com
namespace: my-namespace
annotations:
enonic.cloud/xp7.vhost.mapping.my-mapping-site.source: /
enonic.cloud/xp7.vhost.mapping.my-mapping-site.target: /site/default/master/homepage
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.source: /admin
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.target: /admin
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.idproviders: system
spec:
rules:
- host: my-domain.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: main
port:
number: 8080
- path: /admin
pathType: ImplementationSpecific
backend:
service:
name: main
port:
number: 8080
Deploy this by running:
$ kubectl apply -f simple.yaml
namespace/my-namespace created
xp7deployment.enonic.cloud/my-deployment created
xp7app.enonic.cloud/contentstudio created
xp7config.enonic.cloud/my-config created
ingress.networking.k8s.io/my-domain-com created
Once the XP pods have started you can open up the admin by following the Access admin (bypassing ingress) section or call the ingress controller, if you have one set up.
Cluster example
The values cpu and memory setting in this example are too low for a good cluster setup. They are set this way, so you can try it out on a low resource Kubernetes cluster. |
Let’s deploy a cluster example. Create a file called cluster.yaml
and paste these contents to it:
# Create a namespace
apiVersion: v1
kind: Namespace
metadata:
name: my-namespace
annotations:
# Delete this namespace it the deployment is deleted
enonic.cloud/remove.with.xp7deployment: my-deployment
---
# Create deployment in the namespace
apiVersion: enonic.cloud/v1
kind: Xp7Deployment
metadata:
name: my-deployment
namespace: my-namespace
spec:
enabled: true
xpVersion: 7.13.2
# Create volumes shared by all nodes in this deployment
nodesSharedDisks:
- name: blobstore
size: 1Gi
- name: snapshots
size: 1Gi
- name: export # Dumps and other data
size: 1Gi
# Create nodes
nodeGroups:
# 3 master nodes
- name: master
replicas: 3
data: false
master: true
resources:
cpu: "0.5"
memory: 1Gi
# Volumes private to the node
disks:
- name: index # Node ES index
size: 1Gi
# 2 data nodes
- name: worker
replicas: 2
data: true
master: false
initContainers:
# Preinstall Snapshotter app on worker nodes
- image: enonic/snapshotter:3.1.0
name: snapshotter-deploy
mounts:
- name: deploy
mountPath: /deploy
resources:
cpu: "1"
memory: 1Gi
dirs:
# Snapshotter app copied to deploy folder
- name: deploy
size: 100Mi
mountReadOnly: true
# Volumes private to the node
disks:
- name: index # Node ES index
size: 1Gi
---
# Install content studio
apiVersion: enonic.cloud/v1
kind: Xp7App
metadata:
name: contentstudio
namespace: my-namespace
spec:
url: https://repo.enonic.com/public/com/enonic/app/contentstudio/5.0.3/contentstudio-5.0.3.jar
sha512: ba6b40ebf0808c6fa619ba2a05d07ce3e566eada7e9f3f34c1d280e9d1dcbd1e3c25eff9896d1057c4578ff3f516afa7a905c9e42ddc5e08f1cdf06f7e89774c
---
# Add your own custom config
apiVersion: enonic.cloud/v1
kind: Xp7Config
metadata:
name: my-config
namespace: my-namespace
spec:
nodeGroup: all
file: com.my-app.cfg
data: |
my = config
---
# Expose XP site on frontend nodes through an ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-domain-com-site
namespace: my-namespace
annotations:
enonic.cloud/xp7.vhost.mapping.my-mapping-site.source: /
enonic.cloud/xp7.vhost.mapping.my-mapping-site.target: /site/default/master/homepage
spec:
rules:
- host: my-domain.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: worker
port:
number: 8080
---
# Expose XP admin on admin nodes through an ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-domain-com-admin
namespace: my-namespace
annotations:
# Enable sticy sessions with nginx
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "stickyXpAdmin"
nginx.ingress.kubernetes.io/session-cookie-expires: "129600" # 36 hours
nginx.ingress.kubernetes.io/session-cookie-max-age: "129600" # 36 hours
nginx.ingress.kubernetes.io/session-cookie-change-on-failure: "true"
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.source: /admin
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.target: /admin
enonic.cloud/xp7.vhost.mapping.my-mapping-admin.idproviders: system
spec:
rules:
- host: my-domain.com
http:
paths:
- path: /admin
pathType: ImplementationSpecific
backend:
service:
name: worker
port:
number: 8080
Deploy this by running:
$ kubectl apply -f cluster.yaml
namespace/my-namespace created
xp7deployment.enonic.cloud/my-deployment created
xp7app.enonic.cloud/contentstudio created
xp7config.enonic.cloud/my-config created
ingress.networking.k8s.io/my-domain-com-site created
ingress.networking.k8s.io/my-domain-com-admin created
Once the XP pods have started you can open up the admin by following the Access admin (bypassing ingress) section or call the ingress controller, if you have one set up.