Enabling Hybrid Applications when integrated with Red Hat Advanced Cluster Management

After you integrate IBM Cloud Pak for Multicloud Management with Red Hat® Advanced Cluster Management for Kubernetes and disable the Multicloud Management Core, the Hybrid Application Model capabilities are not enabled. To enable the capabilities for creating and managing hybrid applications, you need to deploy the hybrid application operator to your managed cluster.

With the Hybrid Application Model you can create applications and application resources across different deployment platforms, manage the lifecycle of your applications and infrastructure, and deliver observability for the application’s full stack. This model includes default Kubernetes resource definitions and custom resource definitions to represent and manage application components. Hybrid applications can include application resources that are based on the Kubernetes Special Interest Groups (SIG) Application model and based on custom resources that represent non-Kubernetes resources. For instance, you can use the custom resources to represent non-Kuberenetes resources such as virtual machines, cloud services, and containers. For more information, see Managing hybrid applications.

Procedure

  1. Log in to your hub cluster using the CLI tool:

    oc login --token=*YOUR_TOKEN* --server=*YOUR_SERVER_URL*
    
  2. Configure the hybrid application YAML (hybridapp.yaml) file to change the values for the namespace and cluster-name. The following sample file shows the location of the namespace and cluster-name settings within a full YAML file.

     apiVersion: work.open-cluster-management.io/v1
     kind: ManifestWork
     metadata:
     name: deploy-hybridapp
     namespace: kmc2
     spec:
     workload:
         manifests:
         - apiVersion: apiextensions.k8s.io/v1beta1
         kind: CustomResourceDefinition
         metadata:
             name: deployers.core.hybridapp.io
         spec:
             group: core.hybridapp.io
             names:
             kind: Deployer
             listKind: DeployerList
             plural: deployers
             singular: deployer
             scope: Namespaced
             subresources:
             status: {}
             validation:
             openAPIV3Schema:
                 description: Deployer is the Schema for the deployers API
                 properties:
                 apiVersion:
                     description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
                     type: string
                 kind:
                     description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                     type: string
                 metadata:
                     type: object
                 spec:
                     description: DeployerSpec defines the desired state of Deployer
                     properties:
                     capabilities:
                         items:
                         description: PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to.
                         properties:
                             apiGroups:
                             description: APIGroups is the name of the APIGroup that contains the resources.  If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed.
                             items:
                                 type: string
                             type: array
                             nonResourceURLs:
                             description: NonResourceURLs is a set of partial urls that a user should have access to.  *s are allowed, but only as the full, inal step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"),  but not both.
                             items:
                                 type: string
                             type: array
                             resourceNames:
                             description: ResourceNames is an optional white list of names that the rule applies to.  An empty set means that everything is allowed.
                             items:
                                 type: string
                             type: array
                             resources:
                             description: Resources is a list of resources this rule applies to.  ResourceAll represents all resources.
                             items:
                                 type: string
                             type: array
                             verbs:
                             description: Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule.  VerbAll represents all kinds.
                             items:
                                 type: string
                             type: array
                         required:
                         - verbs
                         type: object
                         type: array
                     clusterScope:
                         type: boolean
                     operatorRef:
                         description: ObjectReference contains enough information to let you inspect or modify the referred object.
                         properties:
                         apiVersion:
                             description: API version of the referent.
                             type: string
                         fieldPath:
                             description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.'
                             type: string
                         kind:
                             description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
                             type: string
                         name:
                             description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
                             type: string
                         namespace:
                             description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
                             type: string
                         resourceVersion:
                             description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
                             type: string
                         uid:
                             description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
                             type: string
                         type: object
                     placementTarget:
                         description: GroupVersionResource unambiguously identifies a resource.  It doesn't anonymously include GroupVersion to avoid automatic coersion.  It doesn't use a GroupVersion to avoid custom marshalling
                         properties:
                         group:
                             type: string
                         resource:
                             type: string
                         version:
                             type: string
                         required:
                         - group
                         - resource
                         - version
                         type: object
                     type:
                         description: 'Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file Add custom validation using kubebuilder tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
                         type: string
                     required:
                     - type
                     type: object
                 status:
                     description: DeployerStatus defines the observed state of Deployer
                     type: object
                 type: object
             version: v1alpha1
             versions:
             - name: v1alpha1
             served: true
             storage: true
         - kind: ServiceAccount
         apiVersion: v1
         metadata:
             name: endpoint-appmgr
             namespace: open-cluster-management-agent-addon
         - kind: ClusterRole
         apiVersion: rbac.authorization.k8s.io/v1
         metadata:
             name: endpoint-appmgr
         rules:
         - apiGroups:
             - '*'
             resources:
             - '*'
             verbs:
             - '*'
         - nonResourceURLs:
             - '*'
             verbs:
             - '*'
         - kind: ClusterRoleBinding
         apiVersion: rbac.authorization.k8s.io/v1
         metadata:
             name: endpoint-appmgr
         roleRef:
             apiGroup: rbac.authorization.k8s.io
             kind: ClusterRole
             name: endpoint-appmgr
         subjects:
             - kind: ServiceAccount
             name: endpoint-appmgr
             namespace: open-cluster-management-agent-addon
         - kind: Deployment
         apiVersion: apps/v1
         metadata:
             name: endpoint-appmgr
             namespace: open-cluster-management-agent-addon
             labels:
             app: application-manager
         spec:
             replicas: 1
             revisionHistoryLimit: 2
             selector:
             matchLabels:
                 app: application-manager
             template:
             metadata:
                 labels:
                 app: application-manager
             annotations:
                 productName: "IBM Multicloud Manager - Klusterlet"
             productID: "c18240a57c1c41969d5e81b39435da6c"
             productVersion: "3.2.1"
           spec:
             serviceAccountName: endpoint-appmgr
             imagePullSecrets:
               - name: ibm-management-pull-secret
             containers:
             - name: ham-resource-discoverer
               image: docker-na-public.artifactory.swg-devops.com/hyc-cloud-private-integration-docker-local/ibmcom/ham-resource-discoverer:2.3.6
               imagePullPolicy: Always
                 env:
                     - name: WATCH_NAMESPACE
                     value: ""
                     - name: POD_NAME
                     valueFrom:
                         fieldRef:
                         fieldPath: metadata.name
                     - name: OPERATOR_NAME
                     value: "ham-resource-discoverer"
                 resources:
                     limits:
                     cpu: 500m
                     memory: 2Gi
                     requests:
                     cpu: 100m
                     memory: 128Mi
                 securityContext:
                     privileged: false
                     readOnlyRootFilesystem: false
                     allowPrivilegeEscalation: false
                     runAsNonRoot: true
                     runAsUser: 1000
                     capabilities:
                     drop:
                     - ALL
                 command: ["/usr/local/bin/entrypoint"]
                 args:
                     - --alsologtostderr
                     - --cluster-name=kmc2
                     - --hub-cluster-configfile=/var/run/klusterlet/kubeconfig
                 livenessProbe:
                     exec:
                     command:
                     - ls
                     initialDelaySeconds: 15
                     periodSeconds: 15
                 readinessProbe:
                     exec:
                     command:
                     - ls
                     initialDelaySeconds: 15
                     periodSeconds: 15
                 volumeMounts:
                     - name: klusterlet-config
                     mountPath: /var/run/klusterlet
                 volumes:
                 - name: klusterlet-config
                     secret:
                     secretName: application-manager-hub-kubeconfig
    
  3. Replace the value for the cluster-name with your-cluster-name in the file:

    sed -i -e 's/managedcluster/<your-cluster-name>/g' hybridapp.yaml
    
  4. Apply the hybridapp.yaml to deploy the hybrid application operator:

    kubectl apply -f hybridapp.yaml
    
  5. Verify that the manifestwork cp4m-hybridapp is created within the namespace your-cluster-name

    kubectl get manifestwork -n <your-cluster-name>
    NAME                                        AGE
    cp4m-hybridapp                            3h16m