What is IBM Cloud Kubernetes Service?
IBM Cloud Kubernetes Service is a managed Kubernetes offering to deliver powerful management tools, an intuitive user experience, and built-in security and isolation to enable rapid delivery of applications—all while leveraging IBM Cloud Services, including cognitive capabilities from Watson. IBM Cloud Kubernetes Service provides native Kubernetes capabilities like intelligent scheduling, self-healing, horizontal scaling, service discovery and load balancing, automated rollouts and rollbacks, and secret and configuration management. Additionally, IBM is adding capabilities to the Kubernetes Service, including simplified cluster management, container security and isolation choices, the ability to design your own cluster and leverage other IBM Cloud services such as Watson for your cognitive applications, completely native Kubernetes CLI and API, and integrated operational tools or support to bring your own tools to ensure operational consistency with other deployments.
Partnering with Portworx
I’m very excited to partner with Joe Gardiner (@grdnrio) from Portworx (@portwx) on this blog post. Learn more about our partnership here and check out the documentation. The rest of this guide is written by Joe.
IBM Db2 is a widely used enterprise database and is part of a larger Db2 family with big data, analytics, and data-streaming use cases. IBM has released and supports a number of DB2 container images on the Docker Store, making it easier than ever to deploy Db2 on your container platform.
As with all data services, running Db2 in a container raises the question: How do I handle my persistent data? Running in production requires a lot of forethought and planning. For example:
How can I failover my Db2 database in the case of a container host failing?
How can I ensure data availability through a snapshot and restore process?
How I can I upgrade my database without corrupting my data or disrupting service?
How can I migrate my containerized Db2 into another cluster or environment?
The aim of this blog post is to answer the above questions by demonstrating a Db2 deployment architecture on Kubernetes using Portworx persistent volumes. Following this post, you’ll understand how to run Db2 in production on Kubernetes.
Getting started with DB2 on Kubernetes
Before getting into the detail of deploying Db2, let’s summarize the steps:
Chose a multicloud container orchestration platform like Kubernetes.
Install a multicloud container storage solution like Portworx.
For a simple and efficient high availability (HA) setup, run a single instance of Db2 and set container volume replication to
io_priority:”high"to schedule Db2 instance on fast storage medium for better IO performance. Use a journal device with your volumes to speed up performance.
Use the Portworx custom block size parameter to support the Db2 512b requirement.
Read on for more details about running an HA Db2 on Kubernetes.
Achieving HA with Db2 on Kubernetes
This blog post makes use of the developer edition of Db2 from the Docker Store. This is a verified and supported image and is perfect for testing, with enterprise images available for production.
Db2 can run in a single-node configuration and in a clustered configuration as described here.
The preferred replication technique with Db2 is the use of an Active-Passive replication set with a primary instance replicating to secondary and tertiary nodes. It makes use of etcd as a source of truth to avoid split brain should a node fail. You can read more about the architecture here.
With Portworx, each Db2 Master and Secondary can have its PVC synchronously replicated. This makes recovering database instances a near-zero cost operation, which results in shorter recovery windows and higher total uptime. With Portworx and Kubernetes, database instance recovery can take less than 180 seconds, which is very rapid considering Db2 can take two minutes to start up.
For deployments where you require replication for data protection but where a single database instance is capable of handling the read requests, a single Db2 pod with Portworx replicated volumes offers a simpler and more cost-effective solution to running HA Db2 on Kubernetes.
This is far less complex to manage and configure and requires a third of the Db2 Pods and therefore s third of the CPU and memory because Portworx is already running on your Kubernetes cluster and synchronously replicates data for all of your applications with great efficiency and scale.
Deploying Db2 on Kubernetes
To start a Db2 deployment, we first need to create a Storage Class. Here we can define how we want to handle the storage for DB2.
kind: StorageClass apiVersion: storage.k8s.io/v1beta1 metadata: name: db2-sc provisioner: kubernetes.io/portworx-volume parameters: repl: "3" block_size: "512b" io_profile: "db" allowVolumeExpansion: true
Note the following parameters in the above Storage Class:
Repl 3: This specifies how many replicated volumes we want across worker nodes in our Kubernetes cluster.
Block_size 512b: This meets the 512 KiB requirement for a relational database in Db2.
Io_profile: db: This implements a write-back flush coalescing algorithm. This algorithm attempts to coalesce multiple syncs that occur within a 50ms window into a single sync.
allowVolumeExpansion: true: This parameter allows us to resize the volume live without any disruption or pod restarts.
Along with the above parameters, we can add Kubernetes snapshot schedules and Kubernetes data encryption policies directly in this storage class definition. This declarative style of configuration is exactly what modern cloud-native infrastructure is all about. No more snowflakes; you can recreate whole environments from source code, including the automation of your common data management tasks.
Next, we need to create the Persistent Volume Claim.
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: db2-pvc annotations: volume.beta.kubernetes.io/storage-class: db2-sc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi
In the above, we are referencing the StorageClass name we created earlier and our storage requirements. Remember, we can resize this later as necessary.
When it comes to deploying Db2, there are a number of things to consider, as shown in the following deployment spec:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: db2 spec: strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 1 type: RollingUpdate replicas: 1 template: metadata: labels: app: db2 spec: schedulerName: stork containers: - name: db2 image: store/ibmcorp/db2_developer_c:188.8.131.52b-x86_64 imagePullPolicy: "IfNotPresent" ports: - containerPort: 50000 env: - name: DB2INST1_PASSWORD value: "somepasswd!" - name: LICENSE value: "accept" - name: TO_CREATE_SAMPLEDB value: "true" - name: DB2INSTANCE value: "db2inst1" volumeMounts: - mountPath: /database name: db2data securityContext: privileged: true securityContext: fsGroup: 1000 imagePullSecrets: - name: regcred volumes: - name: db2data persistentVolumeClaim: claimName: db2-pvc
Firstly, note the image being used. This is available from the Docker Store, but it requires Docker credentials to access it. You can see we’re using an imagePullSecrets parameter with a regcred secret. Follow the Kubernetes docs to set this up.
Next, take note of the environment variables. These are documented on the image docs page once you have access via the Docker Store. Here are the values you can set:
LICENSE=accept DB2INSTANCE=db2inst1 DB2INST1_PASSWORD=password DBNAME=testdb BLU=false ENABLE_ORACLE_COMPATIBILITY=false UPDATEAVAIL=NO TO_CREATE_SAMPLEDB=false REPODB=false IS_OSXFS=false PERSISTENT_HOME=true HADR_ENABLED=false ETCD_ENDPOINT= ETCD_USERNAME= ETCD_PASSWORD=
ETCD values above are used for an HA pod deployment scenario, whereas the approach in this blog is to run a single pod and reply on Portworx and Kubernetes rescheduling to provide resilience.
In the example,
TO_CREATE_SAMPLEDB is set to true. This is to give us some sample data to work with when proving replication and snapshotting. In a real-world scenario, you will probably want to disable this.
You may also notice that we’re setting a fsgroup. The group ID for the db2inst1 user is 1000, so we’re ensuring ownership is set correctly for the volume /database mountpoint. This will allow new databases to be created at this location using the db2 cli with kubectl exec.
Testing Db2 failover
Let’s now walk through a failover scenario. We can simulate a failover by cordoning the node on which Db2 is running and then deleting the Pod. This will force Kubernetes to reschedule the pod.
Once Kubernetes identifies that the pod needs to be rescheduled, it will work with Portworx’s Kubernetes scheduler extender, STORK, to identify which node is best suited to host the restarted pod. In our small environment, any of the two remaining nodes will do because we have a copy of the data on all three nodes. In reality, you will likely have much larger clusters, and that’s when STORK will benefit you by making sure the pod starts on a node where a copy of the data is locally stored. In the unlikely event that your pod cannot be started on one of those nodes, it will be able to start on any of the cluster nodes and access its data seamlessly through the Portworx storage fabric.
This failover should all happen within a very short time window, which is very similar to the Db2 replication configuration described above. This failover is depicted in the figure below:
Db2 storage operations
So it seems that just for Reliability and High Availability alone, it would be worth running Db2 on Kubernetes and Portworx. But, there is a lot more that you can do. So many of the data management operations that are error-prone and time consuming are now going to be fully automated the same way in any cloud environment. First, we’ll show how volumes can be dynamically expanded without reconfiguring or restarting Db2 and then we will show how Snapshots can be easily restored.
Resize DB2 volume on Kubernetes
Data management tasks like these need to be predictable and automatable when it makes sense to do so. Since Portworx volumes are virtual and carved out of your aggregate storage pool on your cluster, we thinly provision the volumes so that the expansion doesn’t immediately require you to add more storage capacity to your cluster.
allowVolumeResize parameter in the StorageClass means we can do this through the Kubernetes CLI by editing the yaml. You can either do this directly with a kubectl edit pvc/db2-pvc or you can edit the spec directly and then reapply it. Either way, you will be able to check the volume and see that it is now 10GB without any disruption being caused to the running application.
Snapshot DB2 on Kubernetes
Snapshots can be scheduled as part of your storage class definition by using the Portworx command line interface (pxctl), or they can be taken on demand by using Stork. Stork uses the external-storage project from kubernetes-incubator to add support for snapshots. The following example shows you how to take a snapshot on demand using yaml in Kubernetes:
apiVersion: volumesnapshot.external-storage.k8s.io/v1 kind: VolumeSnapshot metadata: name: db2-snapshot namespace: default spec: persistentVolumeClaimName: db2-pvc
To learn more about Db2 snapshot schedules, please refer to our docs page.
Stork allows a snapshot to be used as a base from a which a clone PVC can be created. This allows a fresh Db2 deployment containing the snapshot data. You can read more about restoring from a snapshot using Stork in our docs.
As we’ve just seen, you can easily run an HA Db2 container on Kubernetes using Portworx for replication, snapshots, backups, volume resizing, and even encryption. You can see a demo of this in action!