In this technical guide, we examine the StatefulSet’s concept and how to use it, the components of a StatefulSet, and its definition. StatefulSet in the ArvanCloud Container Service is fully compatible with StatefulSet in Kubernetes.
Prerequisites
The only prerequisite for this guide is to have an account and access to the ArvanCloud Container Service. To get started, log in to your account, go to the profile section, create a new API KEY in the Machin User tab, and save it.
To perform the steps of this guide, you need to use ArvanCloud’s command line. Download the command line using this link (put it in your PATH if required) and log in through the command line:
arvan login
Then put the API KEY you received from the site in its continuation.
What Is a StatefulSet?
In the ArvanCloud Container Service, when using persistentVolumeClaim, each disk can be attached to a Pod at the same time, and as a result, you cannot have multiple Replicas of a Pod with a disk in a Deployment.
To use Stateful services or distributed systems, you can use StatefulSet. Two crucial features of StatefulSet that make it suitable for use in these systems are the ability to connect individual disks to Pod Replicas and name Pods incrementally. In a StatefulSet, each Pod contains the name of the StatefulSet and an incrementing number. For example, Pod-1, Pod-2, and…
Creating StatefulSet
To build StatefulSet, you need to enter the required information in yaml format in a file and then submit it to the ArvanCloud Container Service through the command line. Below is a simple example of a StatefulSet for an nginx service, and each of its parts is explained. In this example, it is assumed that the data related to the system log needs to be stored on the persistent disk.
apiVersion: apps/v1 kind: StatefulSet metadata: annotations: labels: app: nginx name: nginx spec: selector: matchLabels: app: nginx serviceName: "nginx" replicas: 3 template: metadata: labels: app: nginx spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx ports: - containerPort: 80 name: http resources: limits: cpu: '2' ephemeral-storage: 4G memory: 1G requests: cpu: '2' ephemeral-storage: 4G memory: 1G volumeMounts: - name: nginx-log mountPath: /var/log/nginx volumeClaimTemplates: - metadata: name: nginx-log spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "standard" resources: requests: storage: 4Gi
Note: indentation is vital in yaml files, and the slightest shift can cause an error or unwanted settings to be returned.
The relevant fields are explained below.
kind: specifies the nature type. This field can have values such as Pod, Service, StatefulSet, Deployment, etc. In fact, like the essences that exist in Kubernetes. In this example, the target is the StatefulSet definition. For this reason, this value is specified.
metadata.name: Specifies the name of the StatefulSet.
spec.replica: Specifies the number of Pods that the StatefulSet will run and manage. Pods are defined in the spec.template.spec section, and the spec.replica field specifies how many (exactly identical) Pods are running according to the definition.
spec.selector.matchLabels: Through this field, the StatefulSet finds out which Pods it should control. The value set for this field must be of key: value format equivalent to the spec.template.metadata.labels field. In this example, this value is set to app: nginx.
spec.serviceName: This field specifies the name of the service that allows access to nginx nodes. This field’s name should be equivalent to the metadata.name of the service used to access nginx pods.
spec.template.metadata.labels: This field assigns labels in the form of key: value to the created pods. In general, the communication between the elements of the ArvanCloud Container Service is done through labels and selectors. For this reason, care must be taken in selecting and determining these values.
spec.template.spec: This section defines the Pod specification that the StatefulSet should handle. In this section, the subcategory spec.template.spec.containers specify the Containers to be executed in each Pod.
spec.template.spec.containers.image: Specifies the Docker Image address of the pod runner.
spec.template.spec.containers.name: specifies the Container’s name that is supposed to be executed in the Pod.
spec.template.spec.containers.imagePullPolicy: Determines when the Docker Image should be pulled again. In this example, it is set equal to IfNotPresent, which is the default value of this field, so that every time the Image is executed, it will be received if the Image is not found on the run node. Other possible values for this field are Always and Never. If Always is selected, it will receive the Cloud Container Image again when the application (Pod) is restarted. However, it is recommended not to set the Never mode because, in this case, the cloud container assumes that the Image is always available on the nodes and does not try to pull it.
spec.template.spec.containers.ports: Specifies the list of ports visible from outside the Container.
spec.template.spec.containers.resources: This section specifies the number of resources the Container will need. It is mandatory to identify these resources in the ArvanCloud Container Service. When determining these resources, one should be careful enough that during execution, the Container should avoid a lack of resources and its execution is not disrupted. This section consists of two sub-sections; Limits and Requests. Each subsection includes CPU, Memory, and Ephemeral-Storage. The values of each should be equal for Limits and Requests. Also, Ephemeral Storage specifies the amount of disk used by the Container. The data stored in it is not stable; if the Pod is restarted, the data in it will return to the default values of the Container, and the changes will be lost. If a persistent disk is required, persistentVolumeClaim can be used.
spec.template.spec.containers.volumeMounts: In this section, the path where the disk needs to be mounted is specified.
spec.template.spec.containers.volumeMounts.name: Since more than one disk can be connected to one Container, they should be named to distinguish the paths.
spec.template.spec.containers.volumeMounts.mountPath: Specifies the address of the path inside the Container whose data we want to write to and read from the permanent disk.
spec.volumeClaimTemplate: This section defines the disks that should be attached to the pods.
spec.volumeClaimTemplate.metadata.name: The name of the disks to be mounted must match spec.template.spec.containers.volumeMounts.name.
spec.volumeClaimTemplate.spec.accessMode: In the ArvanCloud Container Service, this value should be equal to ReadWriteOnce.
spec.volumeClaimTemplate.spec.resources.requests.storage: Specifies the volume of each disk.
Enter and save the above lines in a file called nginx-StatefulSet.yaml. Then submit your StatefulSet to the ArvanCloud Container Service through the command line with the following command.
arvan paas apply -f nginx-StatefulSet.yaml
Then, with the following command, you can see the status of your StatefulSet and its execution on the ArvanCloud Container Service.
arvan paas get sts
The output will be similar to the following:
$ arvan paas get sts NAME DESIRED CURRENT AGE nginx-StatefulSet 3 3 2h
In the output above, NAME specifies the name of the StatefulSet. DESIRED specifies the number of Pods executed by this StatefulSet and is determined by the spec.replica field within the StatefulSet. The CURRENT value tells how many PODs are currently running. Finally, AGE also specifies how long the StatefulSet has been running.
You can also view running pods with the following command.
$ arvan paas get pods NAME READY STATUS RESTARTS AGE nginx-0 1/1 Running 0 14m nginx-1 1/1 Running 0 5m nginx-2 1/1 Running 0 1m
Another way to change the number of Pods is to change the spec.replica field in the StatefulSet configuration file. It is enough to change this value in your file and submit it again to the ArvanCloud Container Service.
You can change the StatefulSet settings directly on the ArvanCloud Container Service with the following command.
arvan paas edit statefulset nginx-StatefulSet
The above command will show the StatefulSet settings in yaml format through the ArvanCloud Container Service default editor. You can apply your changes and then save them. After closing the editor, the settings will be applied automatically, and no other action is required.
Headless Service
Headless service can access StatefulSet Pods from ArvanCloud Container Service. Headless service enables direct access to Pods without Load Balancing incoming traffic. To define Headless Service, it is enough to set spec.clusterIP to none in the Service settings. In this case, you can reach the Pods with the domain name in the form of Pod-1.svc. The following commands show how to define a Headless Service.
apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: http clusterIP: None selector: app: nginx
The relevant fields are explained below.
metadata.name: is the name of the service, which in this example must be equal to the value of spec.serviceName specified in the statefulSet description.
spec.clusterIP: This value should be equal to none to indicate that we intend to define a headless service.
spec.selector: In this section, it is specified to which Pods the incoming traffic should be sent. In this example, Pods related to statefulSet are specified.
According to the above definitions, the following domain names can be used to access each of the defined StatefulSet Pods.
nginx-0.nginx nginx-1.nginx nginx-2.nginx
Since port 80 is used, there is no need to specify the port directly. However, if another port was selected, it should be determined, for example, nginx-0.nginx:80
For more information, you can refer to the Kubernetes and OKD documentation.