Volumes for Docker Compose
PersistentVolumeClaims
created inKubernetesManifest
orHelm
components will not be interfered with. They will work exactly as defined.This article refers to Docker-compose components only:
Application
,Database
,Service
.
If you want to learn why Docker Compose is unsuitable for production and how Bunnyshell can help you transition from docker-compose to Kubernetes, read this article.
Introduction
Bunnyshell enables you to define persistent volumes and attach them to nodes/pods using the volumes
key.
A PersistentVolume
(PV) is a piece of storage in the cluster that has been provisioned by an administrator or dynamically provisioned using a StorageClass
.
It is a resource in the cluster just as how a node is a cluster resource. PVs are volume plugins like Volumes, but have a lifecycle independent of any individual Pod that uses the PV. Read more about Volumes on the official Kubernetes documentation platform.
Types of Bunnyshell volumes
There are two types of volumes users can define in Bunnyshell:
- Disk volumes: persistent volumes with
ReadWriteOnce
access mode.
Such volumes can be attached to a single Kubernetes node. - Network volumes: persistent volumes with
ReadWriteMany
access mode.
Such volumes can be attached to multiple Kubernetes nodes.
Requirements
- An existing Bunnyshell environment
- An existing Kubernetes cluster connected to Bunnyshell
- Make sure you have created the necessary storage classes
Disk and Network volumes
- Are persistent
- Can have configurable sizes and names
- Support subpaths on mount
Warning
Volumes that are not claimed by an environment / component will be removed.
For all persistent volumes, the file mode will be 0777. File modes are set by init containers. Each pod has an init container that modifies permissions for all volumes.
Before the pod container starts, the init container executes a
chown 0777
on all those volumes.
Ā
Specifications
A volumes
key may be added at both the environment level and the component level. Below we will list the volumes for each of the cases.
At an Environment level, Volumes are declared, while at the Component level, they are used (mounted).
Ā
Declaring volumes in Environments
At the Environment level, volumes
are created for the Docker-compose Components (Application
, Database
, Service
) to use.
- name: the name of the volume. This field is mandatory;
- size: the size of the volume. This field is mandatory;
- type: the volume type mapped to Kubernetes cloud volume types. The following options are available:
- disk: can be attached to a single Node;
- network: can be attached to multiple Nodes.
Important
Volumes are isolated at the environment level.
This means that if two
bunnyshell.yaml
configs declare volumes with the same name, Bunnyshell will add the unique ID of their respective environments to their name, making them unique.
Ā
Using volumes in Components
At the Component level, the volumes
property will contain claims to volumes defined at the environment level. It contains the following properties:
- name: the name of the volume claimed. This field is mandatory;
- mount: the path where to mount the volume in the component. This field is mandatory;
- subPath: Path of what to mount into the component.
Volumes will be mounted inside Components based on this spec.
Ā
Validations and constraints
Environment level
- Volume names must be unique. Two volumes can not have the same name;
- The name must consist of lower case alphanumeric characters. It can also contain hyphens
-
, but it must start and end with an alphanumeric character (e.g. 123-abc). - The volume type must be either
disk
, ornetwork
; - The volume size must be greater than zero (any float number is accepted);
- The volume size syntax must be composed of two (case sensitive) parts :
float
andunit
. Unit is a memory unit like Gi.'KB', 'MB', 'GB', 'TB', 'b', 'Gi'
;
An environment volume must be used by a container, otherwise Bunnyshell will show errors.
Component level
- The name must belong to one of the volumes declared at the environment level, otherwise Bunnyshell will show errors;
- The mount field must include a directory path where to mount the volume, in linux format (e.g.
/var/mnt/vol1
) - The name must consist of lower case alphanumeric characters. It can also contain hyphens -, but it must start and end with an alphanumeric character (e.g. 123-abc).
- Two volumes declared at the component level can not be mounted in the same path. The mount path must be unique in list.
Ā
Docker-compose import
All volumes declared in docker-compose will be interpreted as persistent volumes and will have a default size of 1Gi after parsing. These volumes can be found at environment level (declared) or requested by Docker-compose components, pods, init containers or sidecar containers.
The
volumes
attribute fromdocker-compose.yaml
has a different definition compared to thevolumes
attribute frombunnyshell.yaml
.
Here's an example of a volume declared in docker-compose.
services:
nginx:
image: nginx
volumes:
- database_volume
And this is how it will be transformed in bunnyshell.yaml
.
kind: ...
...
components:
-
name: nginx
volumes:
-
name: database_volume
mount: /var/db
volumes:
-
name: database_volume
type: disk
size: 1Gi
Ā
Conversion from Docker-compose - Considerations
- Bunnyshell ignores volumes that are not used by any services (root directive identation 0 in
docker-compose.yaml
file). - Bunnyshell ignores bind and tmpfs Volumes, as well as any local bind that does not use a volume defined under the global key
volumes
. - Volume names will be random values when only the target is defined, as a string.
- If the
StorageClass
was already added in a cluster that was previously connected to Bunnyshell, the user must wait until the cluster is verified to determine whether or not a needed storage class exists. - If a volume is attached to several separate services in
docker-compose.yaml
, or if it is mounted several times inside the same service, it will be migrated as a network volume. - The default size is 1Gi.
- When adding an application that has a volume name already existing inside the environment, a random string will be added to the Volume name to make it unique.
Ā
Example Manifest
# all volumes are persistent
# if you don't need persistance, don't use a mount path
# - the only thing that might not make sense here, is breaking out of the container resource pool
# - I.E. backend php with 1GB disk space having an external mount of 5G
volumes:
-
type: network
# means ReadWriteMany
name: logs-all
size: 10Gi
-
type: disk
# means ReadWriteOnce
# passes validation if used by only 1 ServiceComponent
# passes validation if used by any Init/Sidecar
name: data-mysql
size: 3Gi
components:
-
name: mysql
volumes:
# now we have a persistent database
# what we lack is a way to "kickoff" the database
- name: data-mysql
mountPath: /var/lib/mysql
pod:
init_container:
# this init_container needs to:
# 1. be able to init mysql data
# 2. detect if init has already took place
# 3. not force the volume to become a network volume
- name: init-mysql-data
mounts:
- name: data-mysql
mountPath: /var/lib/mysql
-
name: nginx
volumes:
- name: logs-all
mount: /var/log/nginx
subPath: /nginx
-
name: monitor
volumes:
- name: logs-all
mount: /opt/logs
pod:
sidecar_container:
- name: log-rotate
volumes:
- name: logs-all
mountPath: /opt/logs
Kubernetes Cluster Requirements
In order to be able and create volumes (PersistentVolumeClaim
s) for Docker-compose components, Bunnyshell needs to have its own, dedicated StorageClass
es created in the Kubernetes cluster.
A
StorageClass
provides a way for administrators to describe the "classes" of storage they offer.
Different classes might map to quality-of-service levels, or to backup policies, or to arbitrary policies determined by the cluster administrators.
More information on the StorageClass concept is available on the official Kubernetes documentation.
Updated 14 days ago