A Kubernetes operator to support LAMP applications in a multitenant environment.
You can install the Flightdeck Operator using Helm 3.
helm repo add flightdeck https://ten7.github.io/flightdeck-operator/
helm install flightdeck-operator-system flightdeck/flightdeck-operator
You interact with Flightdeck Operator primarily through Custom Resource Defintions (CRDs). These are like normal Kubernetes (k8s) definitions for Deployments, Statefulsets, and Services, but represent higher order infrastructure managed by the operator.
Typically, you write the CRD you wish to create as a file:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
spec:
replicas: 3
Then, apply it using kubectl:
kubectl apply -f path/to/my/crd.yml
The operator will then deploy all the needed containers, secrets, configmaps, and so on necessary to support the infrastructure you described.
While the YAML for each CRD is different, there are a few pieces of configuration which work the same no matter what.
Many applications provided by the operator are configured to run with multiple instances at the same time, or multiple replicas. You can specify how many using the replicas key:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
spec:
replicas: 3
By default, many k8s defintions created to support a CRD will have the following name pattern:
crdName-crdType
Where:
kind of the CRD, but all lowercase.For example, a MySQLCluster CRD named fdo will result in a StatefulSet named fdo-mysqlcluster. For some complex infrastructure, the name is also prefixed with a component name.
The reason for this naming convention is to allow for multiple instances of the same type to live in the same cluster, and even the same namespace.
The fullnameOverride item overrides the normal name generation process and allows you to specify the complete name instead:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
spec:
fullnameOverride: myCluster
replicas: 3
Often, you only want to customize the Service definition name and port required to support the CRD. You can do this with the service key:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
spec:
replicas: 3
service:
name: mysql
port: 3306
Where:
Many application supported by this operator work best when pair with persistent storage. Otherwise, when a container is destroyed, so is the data. You can configure persistence with the persistence key:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
spec:
persistence:
enabled: true
name: "mysql-data"
existingClaim: "my-mysql-pvc"
size: 20Gi
accessModes:
- ReadWriteOnce
storageClass: "rook-ceph"
path: "/path/to/my/files"
Where:
true), or disabled (false). Optional, defaults to false.fullnameOverride. Ignored when using existingClaim.enabled is true, and not using existingClaim.ReadWriteOnce.You can control where the containers necessary to support the application are placed in the cluster using the nodeSelector and/or affinity keys:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
spec:
nodeSelector:
doks.digitalocean.com/node-pool: my-node-pool
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: flightdeck.ten7.io/phpapplication
operator: In
values:
- drupal
topologyKey: kubernetes.io/hostname
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
Where:
By default, all containers for the application are run without any requests or limits as to memory and CPU resources. You define those requests and limits using the resources key:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
spec:
resources:
requests:
memory: "1024Mi"
cpu: "250m"
limits:
memory: "2048Mi"
cpu: "1000m"
See the Kubernetes documentation on resources for a complete description of use.
The Flightdeck Operator provides three CRDs to work with MySQL:
apiVersion: flightdeck.t7.io/v1
kind: MySQLCluster
metadata:
name: mysqlcluster-sample
namespace: my-database-namespace
spec:
fullnameOverride: myCluster
replicas: 3
mysql_admin_secret: mysql-admin
mysql_readers_secret: mysql-reader
Where:
fullnameOverride followed by -root.fullnameOverride followed by -operator.fullnameOverride followed by -reader.Note, if the secrets do not exist, they will be created and populated with a randomly generated password.
When multiple replicas are used, the first replica is set up as the writer, while all remaining replicas are readers.
To ensure that your databases are preserved if a container is deleted or replaced, use the persistence as described in the Common CRD Configurations section.
Note that replication may not function when using an existing claim or an accessMode of ReadWriteMany.
apiVersion: flightdeck.t7.io/v1
kind: MySQLDatabase
metadata:
name: my-database
spec:
cluster:
name: mysqlcluster-sample
namespace: my-database-namespace
dbName: "my_database"
encoding: "utf8mb4"
collation: "utf8mb4_unicode_ci"
MySQLCluster on which to provision this database.MySQLCluster. Optional, defaults to the current namespace.MySQLDatabase definition.utf8.utf8_general_ci.apiVersion: flightdeck.t7.io/v1
kind: MySQLUser
metadata:
name: my-user
spec:
cluster:
name: fdo
namespace: flightdeck-operator-system
username: "my_user"
host: "%"
password_secret: my-user-pass
privileges:
- database: "my_database"
table: "*"
grants:
- "ALL"
Where:
MySQLCluster on which to provision this database.MySQLCluster. Optional, defaults to the current namespace.MySQLUser definition.%.mysqluser-TheMySQLClusterDefName-TheMySQLUserDefName by default. If non-existent or unspecified, the password itself is autogenerated.The privileges key defines the user's privileges:
The most basic way to deploy a PHP application with the Flightdeck Operator is to create a PhpApplication definition.
apiVersion: flightdeck.t7.io/v1
kind: PhpApplication
metadata:
name: my-php-app
namespace: example-com
spec:
replicas: 3
image: "ten7/flightdeck-web-7.4"
mysqlDatabases:
- name: my-database
namespace: "flightdeck-operator-system"
mysqlUsers:
- name: my-user
namespace: "flightdeck-operator-system"
docroot: "/var/www/html"
storage:
name: "muffy-live-files"
class: "rook-cephfs"
mode: "ReadWriteMany"
size: "5Gi"
path: "/var/www/files"
Where:
ten7/flightdeck-web-8.0. It is highly recommended you override this to your custom container!MySQLDatabase definitions utilized by this application. Optional.MySQLUser definitions utilized by this application. Optional./var/www/html inside the image container.You may wish to configure various hostnames of the application using several keys:
apiVersion: flightdeck.t7.io/v1
kind: PhpApplication
metadata:
name: my-php-app
namespace: example-com
spec:
serverName: "muffy.example.com"
serverAliases:
- "docker.test"
- "muffy.test"
hostAliases:
- ip: "127.0.0.1"
hostnames:
- "docker.test"
- "muffy.test"
Where:
flightdeck.test./etc/hosts for static host name overrides. Optional.You can set environment variables for the application using the env key.
apiVersion: flightdeck.t7.io/v1
kind: PhpApplication
metadata:
name: my-php-app
namespace: example-com
spec:
env:
- name: "FLIGHTDECK_ENVIRONMENT"
value: "live"
Where:
Environment variables are set both for the command line and in the web server.
To configure the PHP engine itself, you can use the php key:
apiVersion: flightdeck.t7.io/v1
kind: PhpApplication
metadata:
name: my-php-app
namespace: example-com
spec:
php:
upload_max_filesize: "128M"
post_max_size: "128M"
See the flightdeck-web-8.0 documentation for full options.
Each web server container also has an accompanying Varnish container, controlled by the varnish key:
apiVersion: flightdeck.t7.io/v1
kind: PhpApplication
metadata:
name: my-php-app
namespace: example-com
spec:
varnish:
image: "ten7/flightdeck-varnish-6.4"
secretName: "varnish-secret"
memSize: "16m"
skipCache:
- "/update\\.php"
- "/core/install\\.php"
- "/admin"
- "/admin/.*"
- "/user"
- "/user/.*"
- "/users/.*"
- "/info/.*"
- "/flag/.*"
- ".*/ahah/.*"
probe:
state: no
probeHost: "muffy.t7test.io"
headers:
- name: "X-Forwarded-Proto"
value: "https"
Where:
ten7/flightdeck-varnish-7.6.fullnameOverride plus -varnish. If empty or doesn't exist, the secret will be autogenerated.32m.Often, you may wish to run a series of commands when deploying a PHP application. For that, you can use the scripts key:
apiVersion: flightdeck.t7.io/v1
kind: PhpApplication
metadata:
name: my-php-app
namespace: example-com
spec:
scripts:
preDeployCheck: |
/path/to/command arg1 arg2
postDeploy: |
/path/to/command arg1 arg2
Where:
0.Due to a design limitation of the operator, the above scripts are run twice.
Often, you want to run background tasks for your PHP applications. While this can be done with normal Kubernetes cronjob definitions, often these tasks rely on the same image, configmaps, secrets, and volumes of the PHP application they support.
For this reason, this operator provides the PhpCronjob kind. It relies on a PhpApplication to provide key configurations:
apiVersion: flightdeck.t7.io/v1
kind: PhpCronjob
metadata:
name: "sleepy-cat"
spec:
phpApplication: "drupal"
image: "ten7/flightdeck-web-7.4"
schedule: "0 * * * *"
suspend: no
args:
- "/bin/bash"
- "-c"
- "sleep 1"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: doks.digitalocean.com/node-pool
operator: In
values:
- web-pool
Where:
PhpApplication definition. Required.image value of the PhpApplication definition.tractorbeam above.To define name-based networking routes to your PHP applications, you can create one or more PhpRoute definitions:
apiVersion: flightdeck.t7.io/v1
kind: PhpRoute
metadata:
name: "apex"
spec:
phpApplication: "drupal"
rules:
- host: "muffy.t7test.io"
paths:
- path: "/"
pathType: "ImplementationSpecific"
bypassVarnish: false
Where:
PhpApplication definition. Required.The rules list specifies how specific paths are mapped to the PHP application.
apiVersion: flightdeck.t7.io/v1
kind: PhpRoute
metadata:
name: "apex"
spec:
phpApplication: "drupal"
rules:
- host: "muffy.t7test.io"
paths:
- path: "/"
pathType: "Prefix"
bypassVarnish: false
Where:
For each item in paths:
Prefix.true to bypass the varnish caching container for the path, false to cache to varnish. Optional, defaults to false.By default, the traffic for a PhpRoute is unencrypted. To enabled encryption, you can use the tls key:
apiVersion: flightdeck.t7.io/v1
kind: PhpRoute
metadata:
name: "apex"
spec:
phpApplication: "drupal"
tls:
state: true
issuer: "lets-encrypt-ops-at-ten7-com"
certSecret: "muffy-cert"
rules:
- host: "muffy.t7test.io"
paths:
- path: "/"
pathType: "ImplementationSpecific"
bypassVarnish: false
Where:
rules in the PhpRoute definition. Optional, defaults to false.PhpRoute definition followed by -cert.Often, you'll want to restrict access to a domain name or path on an existing domain name behind HTTP authentication. Flightdeck Operator supports this when using the NGINX ingress controller.
The first step in configuring this is to create an htpasswd secret containing one or more logins. Instead of requiring you to generate this secret yourself, you can use the Htpasswd definition:
apiVersion: flightdeck.t7.io/v1
kind: Htpasswd
metadata:
name: "muffy-t7test-io"
spec:
logins:
- name: "muffy"
secret: "muffy-auth"
- name: "rocket"
The logins list defines which logins are added to the htpasswd. For each item:
password for the login. Optional, if unspecified or does not exist, the password is autogenerated.Once you have defined an Htpasswd, you can enable HTTP authentication in your PhpRoute using the auth key:
apiVersion: flightdeck.t7.io/v1
kind: PhpRoute
metadata:
name: "apex"
spec:
phpApplication: "drupal"
auth:
state: yes
htpasswd: "muffy-t7test-io"
message: "Poke cat?"
rules:
- host: "muffy.t7test.io"
paths:
- path: "/"
pathType: "ImplementationSpecific"
bypassVarnish: false
Where:
true if auth is defined.Htpasswd definition. Required if auth.state is true.Please enter your login.For high performance PHP application, you might turn a memory-based key/value store such as Memcache. The operator can create a load balanced, multi-tenant Memcache cluster using the MemcacheCluster definition:
---
apiVersion: flightdeck.t7.io/v1
kind: MemcacheCluster
metadata:
name: fdo
namespace: flightdeck-operator-system
spec:
replicas: 3
memory: "128"
threads: "4"
nodeSelector:
key: doks.digitalocean.com/node-pool
value: cache-pool
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: doks.digitalocean.com/node-pool
operator: In
values:
- cache-pool
Where:
256.4.The MemcacheCluster doesn't provide any sort of replication or sharding by itself. Most memcache applications can accept multiple memcache server URLs and load balance internally. This, however, can dramatically increase the required network connections in your cluster, as each applicaiton container needs to connect to n memcache containers.
To reduce this load, this operator provides the ability to spin up a TwemproxyCluster:
apiVersion: flightdeck.t7.io/v1
kind: TwemproxyCluster
metadata:
name: twemproxycluster-sample
spec:
service:
name: twemproxy
port: 22222
pools:
- name: default
port: 11211
hash: fnv1a_64
distribution: ketama
timeout: 400
backlog: 1024
preconnect: true
auto_eject_hosts: true
server_retry_timeout: 30000
server_failure_limit: 30
servers:
- cc04-memcachecluster-0.cc04-memcachecluster:11211:1
- cc04-memcachecluster-1.cc04-memcachecluster:11211:1
- cc04-memcachecluster-2.cc04-memcachecluster:11211:1
Where pools specifies the pools as described in twemproxy.yml, with two exceptions:
listen directive is not available.The server list must specify the internal domain names for the underlying key/value stores. This is either...
podName.serviceName:port:1
...for instances in the same namepace, or...
podName.serviceName.namespaceName.svc.cluster.local:port:1
...for instances in another namespace.
While TwempoxyCluster supports the services key, the port item specifies the Twemproxy statistics port. This is because each pool requires it's own unique port allocation.
Apache Solr is often used by PHP Applications to provide a search function. Instead of single-node Solr instances, you can stand up a multi-tenant Solr Cloud instance using a handful of definitions.
Before creating a SolrCluster, you must also create a ZookeeperCluster. Zookeeper is an Apache project which is used to manage configuration files in a multi-server environment.
apiVersion: flightdeck.t7.io/v1
kind: ZookeeperCluster
metadata:
name: "fdo-sample"
spec:
replicas: 3
persistence:
enabled: true
size: "1Gi"
class: "rook-cephfs"
Before creating a SolrCluster, you must also create a ZookeeperCluster. Zookeeper is an Apache project which is used to manage configuration files in a multi-server environment.
apiVersion: flightdeck.t7.io/v1
kind: SolrCluster
metadata:
name: "fdo"
spec:
zookeeperCluster:
name: "fdo"
namespace: "default"
replicas: 3
persistence:
enabled: true
size: "5Gi"
class: "rook-cephfs"
solrAdmin:
user: solr
secret: "solr-admin-secret"
Where:
name and optionally, the namespace of the zookeeperCluster to use to support the SolrCluster.Content type
Image
Digest
Size
209.7 MB
Last updated
over 4 years ago
docker pull ten7/flightdeck-operator