Deploying IBM® Sterling Control Center Monitor

Creating a Service Account

Now, configMap has been created with all Control Center configuration. The next task is to create a service account. If serviceaccount is created already, image pull secret has been attached with that service account and cluster role binding with Security context constraints (SCCs) has been created for that serviceaccount, then this step will be skipped.

Create Kubernetes service account. In the provided configuration, an image pull secret is created for accessing the image from a secure registry, see Download Container Image. Now, these secrets needs to be added in service account resource.

Following is the ibm-sccm-serviceaccount.yaml file for service account:
apiVersion: v1
kind: ServiceAccount 
metadata:
  name: ibm-sccm-serviceaccount 
  labels:
    app.kubernetes.io/name: sccm 
    app.kubernetes.io/instance: sccm
imagePullSecrets:
- name: sccm-image-secret
Now, create Kubernetes service account resource using following command:
$ oc create -f ibm-sccm-serviceaccount.yaml -n ibm-sccm
Verify service account details using below command:
$ oc describe sa ibm-sccm-serviceaccount -n ibm-sccm

Now, this service account will be utilized to deploy the Control Center using a StatefulSet file.

Persistent Volume Claim (PVC) Configuration for Logs Storage

The next step is to create a Kubernetes Persistent Volume Claim (PVC) to bind with the Persistent Volume (PV), which can be either statically created as mentioned above or dynamically provisioned for the container logs.

ibm-sccm-pvc-ccm.yaml file content for PVC:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: ibm-sccm-pvc-ccm
  labels:
    app.kubernetes.io/name: ibm-scc-pv
    app.kubernetes.io/instance: ibm-sccm
    app.kubernetes.io/managed-by: ibm-sccm-service
    helm.sh/chart: ibm-sccm
    release: ibm-sccm
spec:
  storageClassName: manual
  resources:
    requests:
      storage: 20Gi  
  accessModes:
    - ReadWriteOnce

Now, create a Kubernetes PVC using below command:

$ oc create -f ibm-sccm-pvc-ccm.yaml -n ibm-sccm

Verify that the Persistent Volume (PV) has been successfully bound to the previously created Persistent Volume Claim (PVC) by using the following command:

$ oc get pvc ibm-sccm-pvc-ccm -n ibm-sccm

Creating a StatefulSet in Kubernetes for Application Deployment

There are following three ways to deploy IBM Control Center via the StatefulSet file, based on how resources such as database drivers will be passed to container.

  1. Configuring Resource Passing via PersistentVolume

    In this example StatefulSet file, it is assumed that a Persistent Volume (PV) for user input has been previously created, and the volume has been populated with resources such as database drivers.

    Next step is to create Kubernetes PVC to bind with already created Persistent Volume (PV) using following sample file ibm-sccm-pvc-ui.yaml:
    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: ibm-sccm-pvc-ui
      labels:
        app.kubernetes.io/name: ibm-scc-pv
        app.kubernetes.io/instance: ibm-sccm
        app.kubernetes.io/managed-by: ibm-sccm-service
        helm.sh/chart: ibm-sccm
        release: ibm-sccm
    spec:
      storageClassName: manual
      resources:
        requests:
          storage: 2Gi  
      accessModes:
        - ReadWriteOnce
    
    Now bind the previously created Persistent Volume (PV) with the following command:
    $ oc create -f ibm-sccm-pvc-ui.yaml -n ibm-sccm
    Verify that the Persistent Volume (PV) has been bound with the following command:
    $ oc get pvc ibm-sccm-pvc-ui -n ibm-sccm
    Now, both PVCs have been created for logs and user input resources. Create the StatefulSet file ibm-sccm-statefulset.yaml using the following sample file:
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: ibm-sccm-statefulset
      labels:
        app.kubernetes.io/name: ibm-sccm
        app.kubernetes.io/instance: ibm-sccm
        release: ibm-sccm
        author: IBM
    spec:
      replicas: 1
      selector:
        matchLabels:
          app.kubernetes.io/name: ibm-sccm
          app.kubernetes.io/instance: ibm-sccm
          author: IBM
      template:
        metadata:
          labels:
            app.kubernetes.io/name: ibm-sccm
            app.kubernetes.io/instance: ibm-sccm
            release: ibm-sccm
            author: IBM
          annotations:
            rollme: "KTSWz"
            productID: "6827a92f0c4447ad8685d9ef4107c949"
            productName: "IBM Control Center Monitor Non-Prod Container"
            productVersion: "v6.3"
            productMetric: "VIRTUAL_PROCESSOR_CORE"
            productChargedContainers: "All"
        spec:
          serviceAccountName: ibm-sccm-serviceaccount
          hostNetwork: false
          hostPID: false
          hostIPC: false
          securityContext:
            fsGroup: 65534
            runAsGroup: 0
            runAsNonRoot: true
            runAsUser: 1010 # uid will be used for container user
            seccompProfile:
              type: RuntimeDefault
            supplementalGroups:
            - 65534
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: kubernetes.io/arch
                    operator: In
                    values:
                    - amd64
              preferredDuringSchedulingIgnoredDuringExecution:
            podAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
              preferredDuringSchedulingIgnoredDuringExecution:
            podAntiAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
              preferredDuringSchedulingIgnoredDuringExecution:
          initContainers:
          - name: ibm-sccm-init-secret
            image: "<registry image for pulling image>"
            imagePullPolicy: IfNotPresent
            env:
            - name: ENGINE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: DEBUG_SCRIPT
              value: "true"
            command: ["/app/ccEntrypoint.sh", "populateSecret"]
            volumeMounts:
            - mountPath: /app/CC/conf
              name: cc-volume
              subPathExpr: $(ENGINE_NAME)/conf
            - mountPath: /app/secret_files
              name: scc-secret
            resources:
              limits:
                cpu: 500m
                memory: 2Gi
              requests:
                cpu: 250m
                memory: 1Gi
            securityContext:
                allowPrivilegeEscalation: false
                capabilities:
                  drop:
                  - ALL
                privileged: false
                readOnlyRootFilesystem: false
                runAsUser: 1010
          containers:
            - name: ibm-sccm
              image: "< registry image for pulling image >"
              imagePullPolicy: IfNotPresent
              lifecycle:
                preStop:
                  exec:
                    command: ["/bin/sh", "-c", "/app/ccEntrypoint.sh preStop  > /proc/1/fd/1"]
              env:
                - name: LICENSE
                  value: "true"
                - name: ENGINE_NAME
                  valueFrom:
                    fieldRef:
                      fieldPath: metadata.name
                - name: CC_APP_INTERVAL
                  value: "2h"
                - name: DEBUG_SCRIPT
                  value: "true"
                - name: REBALANCE_SERVERS
                  value: "true"
                - name: CC_BUILD_ENVIRONMENT
                  value: "false"
                - name: TZ
                  value: "Asia/Calcutta"
              volumeMounts:
                - mountPath: /app/CC/log/
                  name: cc-volume
                  subPathExpr: $(ENGINE_NAME)/logs
                - mountPath: /app/CC/conf/
                  name: cc-volume
                  subPathExpr: $(ENGINE_NAME)/conf
                - mountPath: /app/CC/conf-exported
                  name: cc-volume
                  subPathExpr: $(ENGINE_NAME)/conf-exported
                - mountPath: /app/CC/web/ccbase
                  name: cc-volume
                  subPathExpr: $(ENGINE_NAME)/ccbase
                - mountPath: /app/CC/packages/
                  name: cc-volume
                  subPathExpr: packages
                - mountPath: /app/CC/web/ccbase/reports
                  name: cc-volume
                  subPathExpr: reports
                - mountPath: /app/CC/user_inputs/
                  name: cc-volume-user-inputs
                  subPathExpr: user_inputs
                - mountPath: /app/cc_config_file
                  name: scc-param
                  subPath: scc_param_file
                - mountPath: /app/certs_secret_files
                  name: sccm-certs-secret
              securityContext:
                allowPrivilegeEscalation: false
                capabilities:
                  drop:
                  - ALL
                privileged: false
                readOnlyRootFilesystem: false
                runAsUser: 1010
              # Set liveness probe to determine if Control Center is running
              #seLinuxOptions:
                #level: s0:c0
              livenessProbe:
                initialDelaySeconds: 175
                periodSeconds: 120
                timeoutSeconds: 45
                failureThreshold: 10
                exec:
                  command:
                  - bash
                  - -c
                  - /app/ccEntrypoint.sh monitor 58083 # secure web port webHttpsPort given in configmap file
              # Set readiness probe to determine if Control Center is running
              readinessProbe:
                initialDelaySeconds: 175
                periodSeconds: 120
                timeoutSeconds: 15
                failureThreshold: 10
                exec:
                  command:
                  - bash
                  - -c
                  - /app/ccEntrypoint.sh monitor 58083
              startupProbe:
                exec:
                  command:
                  - bash
                  - -c
                  - /app/ccEntrypoint.sh monitor 58083 # secure web port webHttpsPort given in configmap file
                periodSeconds: 120
                failureThreshold: 10
              resources:
                limits:
                  cpu: 3000m
                  ephemeral-storage: 4Gi
                  memory: 8Gi
                requests:
                  cpu: 1500m
                  ephemeral-storage: 2Gi
                  memory: 4Gi
          volumes:
          - name: cc-volume
            persistentVolumeClaim:
              claimName: ibm-sccm-pvc-ccm
          - name: cc-volume-user-inputs
            persistentVolumeClaim:
              claimName: ibm-sccm-pvc-ui
          - name: scc-param
            configMap:
              name: ibm-sccm-cm
          - name: scc-secret
            secret:
              secretName: ibm-sccm-secret
          - name: sccm-certs-secret
            secret:
              secretName: ibm-sccm-certs-secret 
    
  2. Configuring Resource Passing via Wrapper Image

    To pass resources to the container via a wrapper image, it's not necessary to create a user input Persistent Volume, as the required resources are already contained within the image.

    For creating the StatefulSet file for the wrapper image, exclude the following section from the previously created file in Step 1:
    1. From Container’s volumeMounts section:
      - mountPath: /app/CC/user_inputs/ 
       name: cc-volume-user-inputs 
       subPathExpr: user_inputs
      
    2. From StatefulSet’s volumes section:
      - name: cc-volume-user-inputs
       persistentVolumeClaim:
       claimName: ibm-sccm-pvc-ui
      

      The StatefulSet file is now prepared for deployment with wrapper image details.

  3. Configuring Resource Passing via Init-Container Image
    If the init-container image is created with database drivers included, the following lines need to be commented from StatefulSet file created in Step1:
    1. From Container’s volumeMounts section:
      - mountPath: /app/CC/user_inputs/
       name: cc-volume-user-inputs
       subPathExpr: user_inputs
    2. From StatefulSet’s volumes section:
      - name: cc-volume-user-inputs
       persistentVolumeClaim:
       claimName: ibm-sccm-pvc-ui
    3. Include an init-container section alongside the 'ibm-sccm-init-secret' init-container to facilitate the transfer of resources from the init-container image to the main container through a shared 'conf' directory:
      - name: copy-resources
              image: "<init-container image details with tag name>"
              imagePullPolicy: Always
              command: ["sh", "-c", "cp -r /jdbc_drivers/ /app/conf"]
              env:
              - name: ENGINE_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              volumeMounts:
              - mountPath: /app/conf
                name: cc-volume
                subPathExpr: $(ENGINE_NAME)/conf
              resources:
                limits:
                  cpu: 500m
                  memory: 2Gi
                requests:
                  cpu: 250m
                  memory: 1Gi
              securityContext:
                privileged: false
                runAsUser: 1010
                readOnlyRootFilesystem: false
                allowPrivilegeEscalation: false
                capabilities:
                  drop: [ "ALL" ]
      
      Note: If utilizing the init-container image, the path to the database driver will be /app/CC/conf/jdbc_drivers/<driver’s name> within the configuration section.
      Now create a Kubernetes StatefulSet file using following command:
      $ oc create -f ibm-sccm-statefulset.yaml -n ibm-sccm
      After deploying control center, invoke the following command to check statefulset status:
      $ oc get sts ibm-sccm-statefulset -n ibm-sccm 
      NAME	                READY     AGE
      ibm-sccm-statefulset	0/1	10s
      
      Invoke the following command to verify the status of pods:
      $ oc get pods -n ibm-sccm
      NAME                     READY   STATUS    RESTARTS   AGE
      ibm-sccm-statefulset-0   0/1     Running   0          60s
      
      Invoke the following command to verify the logs of the pod:
      $ oc logs -f ibm-sccm-statefulset-0 -n ibm-sccm
      After 6-7 minutes, when pod will be in ready state:
      $ oc get pods -n ibm-sccm
      NAME                     READY   STATUS    RESTARTS   AGE
      ibm-sccm-statefulset-0   1/1     Running   0          8m