4 Deploying TimesTen Databases

This chapter discusses the process for deploying active standby pairs of TimesTen databases. It describes the process for creating TimesTenClassic objects in your environment. It also provides examples that demonstrate how to monitor the provisioning of the active standby pair of TimesTen databases. The chapter concludes with examples that show you how to connect to the database and run operations in it.

Topics:

Understanding the deployment process

The TimesTen Operator extends the Kubernetes API to provide the TimesTenClassic object type. This type provides the definitions you need to successfully deploy your TimesTen databases to the Kubernetes cluster. You customize these definitions for your particular environment. Specifically, you create a YAML file and, in it, you specify the required TimesTenClassic definitions for the TimesTenClassic object. By assigning values to the fields of these definitions, you customize and define your deployment environment. For example, when you supply the oci value for the storageClassName field, you are telling the Operator the name of the storage class you want to use. See Chapter 11, "The TimesTenClassic Object Type" for the object definitions, and the fields that you define in your YAML file.

Examples of the YAML file were introduced previously when discussing ConfigMaps and Secrets, an init container, and other configuration options. (See "Using ConfigMaps and Secrets" for information on ConfigMaps and Secrets. Also see "Using an init container" and "Additional configuration options" for other configuration options.) However, "Defining and creating the TimesTenClassic object" shows you how to define the TimesTenClassic object in detail.

After specifying your configuration in the YAML file, you use the kubectl create command from your Linux development host to create the corresponding TimesTenClassic object in your cluster. After you issue this command, the process for deploying your active standby pair of TimesTen databases begins. You can view this process by issuing kubectl get and kubectl describe commands, such as, kubectl get pods and kubectl describe timestenclassic. Once your databases are deployed, you can then connect to your active database, issue queries, and perform other operations to verify your database is working as it should.

Defining and creating the TimesTenClassic object

Defining your environment involves creating TimesTenClassic objects with attributes customized for your environment. The fields include the name of the image pull secret, the name of your TimesTen image, and the other definitions required to successfully deploy your TimesTen databases. See "The TimesTenClassic object type" for information on defining objects of type TimesTenClassic.

Perform these steps to define and create the TimesTenClassic object:

  1. Create an empty YAML file. You can choose any name, but you may want to use the same name you used for the name of the TimesTenClassic object. (In this example, sample.) The YAML file contains the definitions for the TimesTenClassic object. See "TimesTenClassicSpecSpec" for information on the fields that you must specify in this YAML file as well as the fields that are optional.

    In this example, replace the following. (The values you can replace are represented in bold.)

    • name: Replace sample with the name of your TimesTenClassic object.

    • storageClassName: Replace oci with the name of the storage class used to allocate PersistentVolumes to hold TimesTen.

    • storageSize: Replace 250G with the amount of storage that should be requested for each Pod to hold TimesTen. (This example assumes a production environment and uses 250G for storage. For demonstration purposes, you can use 50G of storage. See the storageSize and the logStorageSize entries in the Table 11-3, "TimesTenClassicSpecSpec" for information.)

    • image: Replace phx.ocir.io/youraccount/tt1814110:3 with the location of the image registry (phx.ocir.io/youraccount) and the image containing TimesTen (tt1814110:3).

    • imagePullSecret: Replace sekret with the image pull secret that Kubernetes should use to fetch the TimesTen image.

    • dbConfigMap: This example uses one ConfigMap (called sample) for the db.ini, the adminUser, and the schema.sql metadata files. This ConfigMap will be included in the ProjectedVolume. This volume is mounted as /ttconfig in the TimesTen containers. See "Using ConfigMaps and Secrets" and "Example using one ConfigMap" for information on ConfigMaps.

    % vi sample.yaml
    
    apiVersion: timesten.oracle.com/v1
    kind: TimesTenClassic
    metadata:
      name: sample
    spec:
      ttspec:
        storageClassName: oci
        storageSize: 250G
        image: phx.ocir.io/youraccount/tt1814110:3
        imagePullSecret: sekret
        dbConfigMap:
        - sample
    
  2. Use the kubectl create command to create the TimesTenClassic object from the contents of the YAML file (in this example, sample.yaml). Doing so begins the process of deploying your active standby pair of TimesTen databases in the Kubernetes cluster.

    % kubectl create -f sample.yaml
    timestenclassic.timesten.oracle.com/sample created
    

You successfully created the TimesTenClassic object in the Kubernetes cluster. The process of deploying your TimesTen databases begins, but is not yet complete.

Monitoring the progress of the active standby pair deployment

You can use various kubectl commands to monitor the progress of the active standby pair deployment. After the deployment is complete and successful, you can connect to the database and run operations in it to verify it is working as it should.

Monitor the state of TimesTenClassic

Use the kubectl get and the kubectl describe commands to monitor the progress of the active standby pair as it is provisioned.

Note:

For the kubectl get timestenclassic and kubectl describe timestenclassic commands, you can alternatively specify kubectl get ttc and kubectl describe ttc respectively. timestenclassic and ttc are synonymous when used in these commands, and return the same results. The first kubectl get and the first kubectl describe examples in this chapter use timestenclassic. The remaining examples in this book use ttc for simplicity.
  1. Use the kubectl get command and review the STATE field. Observe the value is Initializing. The active standby pair provisioning has begun, but is not yet complete.

    % kubectl get timestenclassic sample
    NAME     STATE          ACTIVE   AGE
    sample   Initializing   None     11s
    
  2. Use the kubectl describe command to view the initial provisioning in detail.

    % kubectl describe timestenclassic sample
    Name:         sample
    Namespace:    mynamespace
    Labels:       <none>
    Annotations:  <none>
    API Version:  timesten.oracle.com/v1
    Kind:         TimesTenClassic
    Metadata:
      Creation Timestamp:  2020-05-31T15:35:12Z
      Generation:          1
      Resource Version:    20231755
      Self Link: 
    /apis/timesten.oracle.com/v1/namespaces/mynamespace/timestenclassics/sample
      UID:                 517a8646-a354-11ea-a9fb-0a580aed5e4a
    Spec:
      Ttspec:
        Db Config Map:
          sample
        Image:               phx.ocir.io/youraccount/tt1814110:3
        Image Pull Policy:   Always
        Image Pull Secret:   sekret
        Storage Class Name:  oci
        Storage Size:        250G
    Status:
      Active Pods:       None
      High Level State:  Initializing
      Last Event:        3
      Pod Status:
        Cache Status:
          Cache Agent:        Down
          Cache UID Pwd Set:  false
          N Cache Groups:     0
        Db Status:
          Db:            Unknown
          Db Id:         0
          Db Updatable:  Unknown
        Initialized:     true
        Pod Status:
          Agent:                Down
          Last Time Reachable:  0
          Pod IP:
          Pod Phase:            Pending
        Replication Status:
          Last Time Rep State Changed:  0
          Rep Agent:                    Down
          Rep Peer P State:             Unknown
          Rep Scheme:                   Unknown
          Rep State:                    Unknown
        Times Ten Status:
          Daemon:          Down
          Instance:        Unknown
          Release:         Unknown
        Admin User File:   false
        Cache User File:   false
        Cg File:           false
        High Level State:  Down
        Intended State:    Active
        Name:              sample-0
        Schema File:       false
        Cache Status:
          Cache Agent:        Down
          Cache UID Pwd Set:  false
          N Cache Groups:     0
        Db Status:
          Db:            Unknown
          Db Id:         0
          Db Updatable:  Unknown
        Initialized:     true
        Pod Status:
          Agent:                Down
          Last Time Reachable:  0
          Pod IP:
          Pod Phase:            Pending
        Replication Status:
          Last Time Rep State Changed:  0
          Rep Agent:                    Down
          Rep Peer P State:             Unknown
          Rep Scheme:                   Unknown
          Rep State:                    Unknown
        Times Ten Status:
          Daemon:            Down
          Instance:          Unknown
          Release:           Unknown
        Admin User File:     false
        Cache User File:     false
        Cg File:             false
        High Level State:    Unknown
        Intended State:      Standby
        Name:                sample-1
        Schema File:         false
      Rep Create Statement:  create active standby pair "sample" on 
     "sample-0.sample.mynamespace.svc.cluster.local", "sample" on 
     "sample-1.sample.mynamespace.svc.cluster.local" NO RETURN store "sample" on 
     "sample-0.sample.mynamespace.svc.cluster.local" PORT 4444 FAILTHRESHOLD 0 
     store "sample" on "sample-1.sample.mynamespace.svc.cluster.local" PORT 4444 
     FAILTHRESHOLD  0
      Rep Port:              4444
      Status Version:        1.0
    Events:
      Type  Reason  Age   From       Message
      ----  ------  ----  ----       -------
      -     Create  50s   ttclassic  Secret tt517a8646-a354-11ea-a9fb-0a580aed5e4a
     created
      -     Create  50s   ttclassic  Service sample created
      -     Create  50s   ttclassic  StatefulSet sample created
    
  3. Use the kubectl get command again to see if value of the STATE field has changed. In this example, the value is Normal, indicating the active standby pair of databases are now provisioned and the process is complete.

    % kubectl get ttc sample
    NAME     STATE    ACTIVE     AGE
    sample   Normal   sample-0   3m5s
    
  4. Use the kubectl describe command again to view the active standby pair provisioning in detail.

    Note: In this example, the now Normal line displays on its own line. In the actual output, this line does not display as its own line, but at the end of the StateChange previous line.

    % kubectl describe ttc sample
    Name:         sample
    Namespace:    mynamespace
    Labels:       <none>
    Annotations:  <none>
    API Version:  timesten.oracle.com/v1
    Kind:         TimesTenClassic
    Metadata:
      Creation Timestamp:  2020-05-31T15:35:12Z
      Generation:          1
      Resource Version:    20232668
      Self Link:
    /apis/timesten.oracle.com/v1/namespaces/mynamespace/timestenclassics/sample 
      UID:                 517a8646-a354-11ea-a9fb-0a580aed5e4a
    Spec:
      Ttspec:
        Db Config Map:
          sample
        Image:               phx.ocir.io/youraccount/tt1814110:3
        Image Pull Policy:   Always
        Image Pull Secret:   sekret
        Storage Class Name:  oci
        Storage Size:        250G
    Status:
      Active Pods:       sample-0
      High Level State:  Normal
      Last Event:        35
      Pod Status:
        Cache Status:
          Cache Agent:        Not Running
          Cache UID Pwd Set:  true
          N Cache Groups:     0
        Db Status:
          Db:            Loaded
          Db Id:         26
          Db Updatable:  Yes
        Initialized:     true
        Pod Status:
          Agent:                Up
          Last Time Reachable:  1590939597
          Pod IP:               192.0.2.1
          Pod Phase:            Running
        Replication Status:
          Last Time Rep State Changed:  0
          Rep Agent:                    Running
          Rep Peer P State:             start
          Rep Scheme:                   Exists
          Rep State:                    ACTIVE
        Times Ten Status:
          Daemon:          Up
          Instance:        Exists
          Release:         18.1.4.11.0
        Admin User File:   true
        Cache User File:   false
        Cg File:           false
        High Level State:  Healthy
        Intended State:    Active
        Name:              sample-0
        Schema File:       true
        Cache Status:
          Cache Agent:        Not Running
          Cache UID Pwd Set:  true
          N Cache Groups:     0
        Db Status:
          Db:            Loaded
          Db Id:         26
          Db Updatable:  No
        Initialized:     true
        Pod Status:
          Agent:                Up
          Last Time Reachable:  1590939597
          Pod IP:               192.0.2.2
          Pod Phase:            Running
        Replication Status:
          Last Time Rep State Changed:  1590939496
          Rep Agent:                    Running
          Rep Peer P State:             start
          Rep Scheme:                   Exists
          Rep State:                    STANDBY
        Times Ten Status:
          Daemon:            Up
          Instance:          Exists
          Release:           18.1.4.11.0
        Admin User File:     true
        Cache User File:     false
        Cg File:             false
        High Level State:    Healthy
        Intended State:      Standby
        Name:                sample-1
        Schema File:         true
      Rep Create Statement:  create active standby pair "sample" on 
    "sample-0.sample.mynamespace.svc.cluster.local", "sample" on 
    "sample-1.sample.mynamespace.svc.cluster.local" NO RETURN store "sample" on 
    "sample-0.sample.mynamespace.svc.cluster.local" PORT 4444 FAILTHRESHOLD 0 
    store "sample" on "sample-1.sample.mynamespace.svc.cluster.local" PORT 4444 
    FAILTHRESHOLD 0
      Rep Port:              4444
      Status Version:        1.0
    Events:
      Type  Reason       Age    From       Message
      ----  ------       ----   ----       -------
      -     Create       4m43s  ttclassic  Secret 
    tt517a8646-a354-11ea-a9fb-0a580aed5e4a created
      -     Create       4m43s  ttclassic  Service sample created
      -     Create       4m43s  ttclassic  StatefulSet sample created
      -     StateChange  3m47s  ttclassic  Pod sample-0 Daemon Unknown
      -     StateChange  3m47s  ttclassic  Pod sample-0 CacheAgent Unknown
      -     StateChange  3m47s  ttclassic  Pod sample-0 RepAgent Unknown
      -     StateChange  3m47s  ttclassic  Pod sample-1 Daemon Unknown
      -     StateChange  3m47s  ttclassic  Pod sample-1 CacheAgent Unknown
      -     StateChange  3m47s  ttclassic  Pod sample-1 RepAgent Unknown
      -     StateChange  3m26s  ttclassic  Pod sample-0 Agent Up
      -     StateChange  3m26s  ttclassic  Pod sample-0 Release 18.1.4.11.0
      -     StateChange  3m26s  ttclassic  Pod sample-0 Daemon Down
      -     StateChange  3m26s  ttclassic  Pod sample-1 Agent Up
      -     StateChange  3m26s  ttclassic  Pod sample-1 Release 18.1.4.11.0
      -     StateChange  3m26s  ttclassic  Pod sample-1 Daemon Down
      -     StateChange  3m26s  ttclassic  Pod sample-0 Daemon Up
      -     StateChange  3m25s  ttclassic  Pod sample-1 Daemon Up
      -     StateChange  2m13s  ttclassic  Pod sample-0 RepState IDLE
      -     StateChange  2m13s  ttclassic  Pod sample-0 Database Updatable
      -     StateChange  2m13s  ttclassic  Pod sample-0 CacheAgent Not Running
      -     StateChange  2m13s  ttclassic  Pod sample-0 RepAgent Not Running
      -     StateChange  2m13s  ttclassic  Pod sample-0 RepScheme None
      -     StateChange  2m13s  ttclassic  Pod sample-0 Database Loaded
      -     StateChange  2m11s  ttclassic  Pod sample-0 RepAgent Running
      -     StateChange  2m10s  ttclassic  Pod sample-0 RepScheme Exists
      -     StateChange  2m10s  ttclassic  Pod sample-0 RepState ACTIVE
      -     StateChange  113s   ttclassic  Pod sample-1 Database Loaded
      -     StateChange  113s   ttclassic  Pod sample-1 Database Not Updatable
      -     StateChange  113s   ttclassic  Pod sample-1 CacheAgent Not Running
      -     StateChange  113s   ttclassic  Pod sample-1 RepAgent Not Running
      -     StateChange  113s   ttclassic  Pod sample-1 RepScheme Exists
      -     StateChange  113s   ttclassic  Pod sample-1 RepState IDLE
      -     StateChange  106s   ttclassic  Pod sample-1 RepAgent Running
      -     StateChange  101s   ttclassic  Pod sample-1 RepState STANDBY
      -     StateChange  101s   ttclassic  TimesTenClassic was Initializing, 
    now Normal
    

Your active standby pair of TimesTen databases are successfully deployed (as indicated by Normal.) There are two TimesTen databases, configured as an active standby pair. One database is active. (In this example, sample-0 is the active database, as indicated by Rep State ACTIVE). The other database is standby. (In this example, sample-1 is the standby database as indicated by Rep State STANDBY). The active database can be modified and queried. Changes made on the active database are replicated to the standby database. If the active database fails, the Operator automatically promotes the standby database to be the active. The formerly active database will be repaired or replaced, and will then become the standby.

Verify the underlying objects exist

The Operator creates other underlying objects automatically. Verify that these objects are created.

  1. StatefulSet:

    % kubectl get statefulset sample
    NAME     READY   AGE
    sample   2/2     8m21s
    
  2. Service:

    % kubectl get service sample
    NAME     TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
    sample   ClusterIP   None         <none>        6625/TCP   9m28s
    
  3. Pods:

    % kubectl get pods
    NAME                                        READY   STATUS    RESTARTS   AGE
    sample-0                                    2/2     Running   0          10m
    sample-1                                    2/2     Running   0          10m
    timestenclassic-operator-5d7dcc7948-8mnz4   1/1     Running   0          11h
    
  4. PersistentVolumeClaims (PVCs):

    % kubectl get pvc
    NAME                         STATUS   VOLUME 
    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    tt-persistent-sample-0       Bound
    ocid1.volume.oc1.phx.abyhqljrbxcgzyixa4pmmcwiqxgqclc7gxvdnoty367w2qn26tij6kfpx
    6qq
    250Gi       RWO            oci            10m
    tt-persistent-sample-1       Bound
    ocid1.volume.oc1.phx.abyhqljtt4qxxoj5jqiskriskh66hakaw326rbza4uigmuaezdnu53qhh
    oaa
    250Gi       RWO            oci            10m
    

Verify connection to the active database

You can run the kubectl exec command to invoke shells in your Pods and control TimesTen, which is running in those Pods. TimesTen runs in the Pods as the oracle user. Once you have established a shell in the Pod, use the su - oracle command to switch to the oracle user. After you switch to the oracle user, verify you can connect to the sample database, and that the information from the metadata files is correct. You can optionally run queries against the database or any other operations.

  1. Establish a shell in the Pod and switch to the oracle user.

    % kubectl exec -it sample-0 -c tt -- /usr/bin/su - oracle 
    
  2. Connect to the sample database. Verify the information in the metadata files is in the database correctly. For example, attempt to connect to the database as the scott user. Check that the PermSize value of 200 is correct. Check that the scott.emp table exists.

     % ttIsql sample
     
    Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
    Type ? or "help" for help, type "exit" to quit ttIsql.
     
     
     
    connect "DSN=sample";
    Connection successful:
    DSN=sample;UID=oracle;DataStore=/tt/home/oracle/datastore/sample;
    DatabaseCharacterSet=AL32UTF8;ConnectionCharacterSet=US7ASCII;PermSize=200;
    DDLReplicationLevel=3;
    (Default setting AutoCommit=1)
    
    Command> connect adding "uid=scott;pwd=tiger" as scott;
    Connection successful:
    DSN=sample;UID=scott;DataStore=/tt/home/oracle/datastore/sample;
    DatabaseCharacterSet=AL32UTF8;ConnectionCharacterSet=US7ASCII;PermSize=200;
    DDLReplicationLevel=3;
    (Default setting AutoCommit=1)
    scott: Command> tables;
      SCOTT.EMP
    1 table found.